<commit_before>package gorm

import (
	"errors"
	"fmt"
	"go/ast"
	"strings"
	"time"

	"reflect"
	"regexp"
)

type Scope struct {
	Value         interface{}
	indirectValue *reflect.Value
	Search        *search
	Sql           string
	SqlVars       []interface{}
	db            *DB
	_values       map[string]interface{}
	skipLeft      bool
	primaryKey    string
}

func (scope *Scope) IndirectValue() reflect.Value {
	if scope.indirectValue == nil {
		value := reflect.Indirect(reflect.ValueOf(scope.Value))
		scope.indirectValue = &value
	}
	return *scope.indirectValue
}

// NewScope create scope for callbacks, including DB's search information
func (db *DB) NewScope(value interface{}) *Scope {
	db.Value = value
	return &Scope{db: db, Search: db.search, Value: value, _values: map[string]interface{}{}}
}

// New create a new Scope without search information
func (scope *Scope) New(value interface{}) *Scope {
	return &Scope{db: scope.db.parent, Search: &search{}, Value: value}
}

// NewDB create a new DB without search information
func (scope *Scope) NewDB() *DB {
	return scope.db.new()
}

// DB get *sql.DB
func (scope *Scope) DB() sqlCommon {
	return scope.db.db
}

// SkipLeft skip remaining callbacks
func (scope *Scope) SkipLeft() {
	scope.skipLeft = true
}

// Quote used to quote database column name according to database dialect
func (scope *Scope) Quote(str string) string {
	return scope.Dialect().Quote(str)
}

// Dialect get dialect
func (scope *Scope) Dialect() Dialect {
	return scope.db.parent.dialect
}

// Err write error
func (scope *Scope) Err(err error) error {
	if err != nil {
		scope.db.err(err)
	}
	return err
}

// Log print log message
func (scope *Scope) Log(v ...interface{}) {
	scope.db.log(v...)
}

// HasError check if there are any error
func (scope *Scope) HasError() bool {
	return scope.db.Error != nil
}

// PrimaryKey get the primary key's column name
func (scope *Scope) PrimaryKey() string {
	if scope.primaryKey != "" {
		return scope.primaryKey
	}

	scope.primaryKey = ToSnake(GetPrimaryKey(scope.Value))
	return scope.primaryKey
}

// PrimaryKeyZero check the primary key is blank or not
func (scope *Scope) PrimaryKeyZero() bool {
	return isBlank(reflect.ValueOf(scope.PrimaryKeyValue()))
}

// PrimaryKeyValue get the primary key's value
func (scope *Scope) PrimaryKeyValue() interface{} {
	if scope.IndirectValue().Kind() == reflect.Struct {
		if field := scope.IndirectValue().FieldByName(SnakeToUpperCamel(scope.PrimaryKey())); field.IsValid() {
			return field.Interface()
		}
	}
	return 0
}

// HasColumn to check if has column
func (scope *Scope) HasColumn(name string) bool {
	_, result := scope.FieldValueByName(name)
	return result
}

// FieldValueByName to get column's value and existence
func (scope *Scope) FieldValueByName(name string) (interface{}, bool) {
	return FieldValueByName(name, scope.Value)
}

// SetColumn to set the column's value
func (scope *Scope) SetColumn(column string, value interface{}) bool {
	if scope.Value == nil {
		return false
	}

	return setFieldValue(scope.IndirectValue().FieldByName(SnakeToUpperCamel(column)), value)
}

// CallMethod invoke method with necessary argument
func (scope *Scope) CallMethod(name string) {
	if scope.Value == nil {
		return
	}

	call := func(value interface{}) {
		if fm := reflect.ValueOf(value).MethodByName(name); fm.IsValid() {
			fi := fm.Interface()
			if f, ok := fi.(func()); ok {
				f()
			} else if f, ok := fi.(func(s *Scope)); ok {
				f(scope)
			} else if f, ok := fi.(func(s *DB)); ok {
				f(scope.db.new())
			} else if f, ok := fi.(func() error); ok {
				scope.Err(f())
			} else if f, ok := fi.(func(s *Scope) error); ok {
				scope.Err(f(scope))
			} else if f, ok := fi.(func(s *DB) error); ok {
				scope.Err(f(scope.db.new()))
			} else {
				scope.Err(errors.New(fmt.Sprintf("unsupported function %v", name)))
			}
		}
	}

	if values := scope.IndirectValue(); values.Kind() == reflect.Slice {
		for i := 0; i < values.Len(); i++ {
			call(values.Index(i).Addr().Interface())
		}
	} else {
		call(scope.Value)
	}
}

// AddToVars add value as sql's vars, gorm will escape them
func (scope *Scope) AddToVars(value interface{}) string {
	scope.SqlVars = append(scope.SqlVars, value)
	return scope.Dialect().BinVar(len(scope.SqlVars))
}

// TableName get table name
var pluralMapKeys = []*regexp.Regexp{regexp.MustCompile("ch$"), regexp.MustCompile("ss$"), regexp.MustCompile("sh$"), regexp.MustCompile("day$"), regexp.MustCompile("y$"), regexp.MustCompile("x$"), regexp.MustCompile("([^s])s?$")}
var pluralMapValues = []string{"ches", "sses", "shes", "days", "ies", "xes", "${1}s"}

func (scope *Scope) TableName() string {
	if scope.Search != nil && len(scope.Search.TableName) > 0 {
		return scope.Search.TableName
	} else {
		if scope.Value == nil {
			scope.Err(errors.New("can't get table name"))
			return ""
		}

		data := scope.IndirectValue()
		if data.Kind() == reflect.Slice {
			elem := data.Type().Elem()
			if elem.Kind() == reflect.Ptr {
				elem = elem.Elem()
			}
			data = reflect.New(elem).Elem()
		}

		if fm := data.MethodByName("TableName"); fm.IsValid() {
			if v := fm.Call([]reflect.Value{}); len(v) > 0 {
				if result, ok := v[0].Interface().(string); ok {
					return result
				}
			}
		}

		str := ToSnake(data.Type().Name())

		if !scope.db.parent.singularTable {
			for index, reg := range pluralMapKeys {
				if reg.MatchString(str) {
					return reg.ReplaceAllString(str, pluralMapValues[index])
				}
			}
		}

		return str
	}
}

func (scope *Scope) QuotedTableName() string {
	if scope.Search != nil && len(scope.Search.TableName) > 0 {
		return scope.Search.TableName
	} else {
		keys := strings.Split(scope.TableName(), ".")
		for i, v := range keys {
			keys[i] = scope.Quote(v)
		}
		return strings.Join(keys, ".")
	}
}

// CombinedConditionSql get combined condition sql
func (scope *Scope) CombinedConditionSql() string {
	return scope.joinsSql() + scope.whereSql() + scope.groupSql() +
		scope.havingSql() + scope.orderSql() + scope.limitSql() + scope.offsetSql()
}

func (scope *Scope) FieldByName(name string) (field *Field, ok bool) {
	var f reflect.StructField
	if scope.Value != nil {
		if scope.IndirectValue().Kind() == reflect.Struct {
			if f, ok = scope.IndirectValue().Type().FieldByName(SnakeToUpperCamel(name)); ok {
				field = scope.fieldFromStruct(f)
			}
		}
	}
	return
}

func (scope *Scope) fieldFromStruct(fieldStruct reflect.StructField) *Field {
	var field Field
	field.Name = fieldStruct.Name
	field.DBName = ToSnake(fieldStruct.Name)

	value := scope.IndirectValue().FieldByName(fieldStruct.Name)
	indirectValue := reflect.Indirect(value)
	field.Value = value.Interface()
	field.IsBlank = isBlank(value)

	// Search for primary key tag identifier
	settings := parseTagSetting(fieldStruct.Tag.Get("gorm"))
	if scope.PrimaryKey() == field.DBName {
		field.IsPrimaryKey = true
	}

	field.Tag = fieldStruct.Tag
	field.SqlTag = scope.sqlTagForField(&field)

	if !field.IsIgnored {
		// parse association
		if !indirectValue.IsValid() {
			indirectValue = reflect.New(value.Type())
		}
		typ := indirectValue.Type()
		foreignKey := SnakeToUpperCamel(settings["FOREIGNKEY"])
		associationForeignKey := SnakeToUpperCamel(settings["ASSOCIATIONFOREIGNKEY"])
		many2many := settings["MANY2MANY"]
		scopeTyp := scope.IndirectValue().Type()

		switch indirectValue.Kind() {
		case reflect.Slice:
			typ = typ.Elem()

			if typ.Kind() == reflect.Struct {
				if foreignKey == "" {
					foreignKey = scopeTyp.Name() + "Id"
				}
				if associationForeignKey == "" {
					associationForeignKey = typ.Name() + "Id"
				}

				// if not many to many, foreign key could be null
				if many2many == "" {
					if !reflect.New(typ).Elem().FieldByName(foreignKey).IsValid() {
						foreignKey = ""
					}
				}

				field.Relationship = &relationship{
					JoinTable:             many2many,
					ForeignKey:            foreignKey,
					AssociationForeignKey: associationForeignKey,
					Kind: "has_many",
				}

				if many2many != "" {
					field.Relationship.Kind = "many_to_many"
				}
			}
		case reflect.Struct:
			if !field.IsTime() && !field.IsScanner() {
				if foreignKey == "" && scope.HasColumn(field.Name+"Id") {
					field.Relationship = &relationship{ForeignKey: field.Name + "Id", Kind: "belongs_to"}
				} else if scope.HasColumn(foreignKey) {
					field.Relationship = &relationship{ForeignKey: foreignKey, Kind: "belongs_to"}
				} else {
					if foreignKey == "" {
						foreignKey = scopeTyp.Name() + "Id"
					}
					if reflect.New(typ).Elem().FieldByName(foreignKey).IsValid() {
						field.Relationship = &relationship{ForeignKey: foreignKey, Kind: "has_one"}
					}
				}
			}
		}
	}
	return &field
}

// Fields get value's fields
func (scope *Scope) Fields() (fields []*Field) {
	if scope.IndirectValue().IsValid() {
		scopeTyp := scope.IndirectValue().Type()
		for i := 0; i < scopeTyp.NumField(); i++ {
			fieldStruct := scopeTyp.Field(i)
			if !ast.IsExported(fieldStruct.Name) {
				continue
			}
			fields = append(fields, scope.fieldFromStruct(fieldStruct))
		}
	}
	return
}

// Raw set sql
func (scope *Scope) Raw(sql string) *Scope {
	scope.Sql = strings.Replace(sql, "$$", "?", -1)
	return scope
}

// Exec invoke sql
func (scope *Scope) Exec() *Scope {
	defer scope.Trace(time.Now())

	if !scope.HasError() {
		result, err := scope.DB().Exec(scope.Sql, scope.SqlVars...)
		if scope.Err(err) == nil {
			if count, err := result.RowsAffected(); err == nil {
				scope.db.RowsAffected = count
			}
		}
	}
	return scope
}

// Set set value by name
func (scope *Scope) Set(name string, value interface{}) *Scope {
	scope._values[name] = value
	return scope
}

// Get get value by name
func (scope *Scope) Get(name string) (value interface{}, ok bool) {
	value, ok = scope._values[name]
	return
}

// Trace print sql log
func (scope *Scope) Trace(t time.Time) {
	if len(scope.Sql) > 0 {
		scope.db.slog(scope.Sql, t, scope.SqlVars...)
	}
}

// Begin start a transaction
func (scope *Scope) Begin() *Scope {
	if db, ok := scope.DB().(sqlDb); ok {
		if tx, err := db.Begin(); err == nil {
			scope.db.db = interface{}(tx).(sqlCommon)
			scope.Set("gorm:started_transaction", true)
		}
	}
	return scope
}

// CommitOrRollback commit current transaction if there is no error, otherwise rollback it
func (scope *Scope) CommitOrRollback() *Scope {
	if _, ok := scope.Get("gorm:started_transaction"); ok {
		if db, ok := scope.db.db.(sqlTx); ok {
			if scope.HasError() {
				db.Rollback()
			} else {
				db.Commit()
			}
			scope.db.db = scope.db.parent.db
		}
	}
	return scope
}
<commit_msg>Don't raise error when get TableName even Scope has no db<commit_after>package gorm

import (
	"errors"
	"fmt"
	"go/ast"
	"strings"
	"time"

	"reflect"
	"regexp"
)

type Scope struct {
	Value         interface{}
	indirectValue *reflect.Value
	Search        *search
	Sql           string
	SqlVars       []interface{}
	db            *DB
	_values       map[string]interface{}
	skipLeft      bool
	primaryKey    string
}

func (scope *Scope) IndirectValue() reflect.Value {
	if scope.indirectValue == nil {
		value := reflect.Indirect(reflect.ValueOf(scope.Value))
		scope.indirectValue = &value
	}
	return *scope.indirectValue
}

// NewScope create scope for callbacks, including DB's search information
func (db *DB) NewScope(value interface{}) *Scope {
	db.Value = value
	return &Scope{db: db, Search: db.search, Value: value, _values: map[string]interface{}{}}
}

// New create a new Scope without search information
func (scope *Scope) New(value interface{}) *Scope {
	return &Scope{db: scope.db.parent, Search: &search{}, Value: value}
}

// NewDB create a new DB without search information
func (scope *Scope) NewDB() *DB {
	return scope.db.new()
}

// DB get *sql.DB
func (scope *Scope) DB() sqlCommon {
	return scope.db.db
}

// SkipLeft skip remaining callbacks
func (scope *Scope) SkipLeft() {
	scope.skipLeft = true
}

// Quote used to quote database column name according to database dialect
func (scope *Scope) Quote(str string) string {
	return scope.Dialect().Quote(str)
}

// Dialect get dialect
func (scope *Scope) Dialect() Dialect {
	return scope.db.parent.dialect
}

// Err write error
func (scope *Scope) Err(err error) error {
	if err != nil {
		scope.db.err(err)
	}
	return err
}

// Log print log message
func (scope *Scope) Log(v ...interface{}) {
	scope.db.log(v...)
}

// HasError check if there are any error
func (scope *Scope) HasError() bool {
	return scope.db.Error != nil
}

// PrimaryKey get the primary key's column name
func (scope *Scope) PrimaryKey() string {
	if scope.primaryKey != "" {
		return scope.primaryKey
	}

	scope.primaryKey = ToSnake(GetPrimaryKey(scope.Value))
	return scope.primaryKey
}

// PrimaryKeyZero check the primary key is blank or not
func (scope *Scope) PrimaryKeyZero() bool {
	return isBlank(reflect.ValueOf(scope.PrimaryKeyValue()))
}

// PrimaryKeyValue get the primary key's value
func (scope *Scope) PrimaryKeyValue() interface{} {
	if scope.IndirectValue().Kind() == reflect.Struct {
		if field := scope.IndirectValue().FieldByName(SnakeToUpperCamel(scope.PrimaryKey())); field.IsValid() {
			return field.Interface()
		}
	}
	return 0
}

// HasColumn to check if has column
func (scope *Scope) HasColumn(name string) bool {
	_, result := scope.FieldValueByName(name)
	return result
}

// FieldValueByName to get column's value and existence
func (scope *Scope) FieldValueByName(name string) (interface{}, bool) {
	return FieldValueByName(name, scope.Value)
}

// SetColumn to set the column's value
func (scope *Scope) SetColumn(column string, value interface{}) bool {
	if scope.Value == nil {
		return false
	}

	return setFieldValue(scope.IndirectValue().FieldByName(SnakeToUpperCamel(column)), value)
}

// CallMethod invoke method with necessary argument
func (scope *Scope) CallMethod(name string) {
	if scope.Value == nil {
		return
	}

	call := func(value interface{}) {
		if fm := reflect.ValueOf(value).MethodByName(name); fm.IsValid() {
			fi := fm.Interface()
			if f, ok := fi.(func()); ok {
				f()
			} else if f, ok := fi.(func(s *Scope)); ok {
				f(scope)
			} else if f, ok := fi.(func(s *DB)); ok {
				f(scope.db.new())
			} else if f, ok := fi.(func() error); ok {
				scope.Err(f())
			} else if f, ok := fi.(func(s *Scope) error); ok {
				scope.Err(f(scope))
			} else if f, ok := fi.(func(s *DB) error); ok {
				scope.Err(f(scope.db.new()))
			} else {
				scope.Err(errors.New(fmt.Sprintf("unsupported function %v", name)))
			}
		}
	}

	if values := scope.IndirectValue(); values.Kind() == reflect.Slice {
		for i := 0; i < values.Len(); i++ {
			call(values.Index(i).Addr().Interface())
		}
	} else {
		call(scope.Value)
	}
}

// AddToVars add value as sql's vars, gorm will escape them
func (scope *Scope) AddToVars(value interface{}) string {
	scope.SqlVars = append(scope.SqlVars, value)
	return scope.Dialect().BinVar(len(scope.SqlVars))
}

// TableName get table name
var pluralMapKeys = []*regexp.Regexp{regexp.MustCompile("ch$"), regexp.MustCompile("ss$"), regexp.MustCompile("sh$"), regexp.MustCompile("day$"), regexp.MustCompile("y$"), regexp.MustCompile("x$"), regexp.MustCompile("([^s])s?$")}
var pluralMapValues = []string{"ches", "sses", "shes", "days", "ies", "xes", "${1}s"}

func (scope *Scope) TableName() string {
	if scope.Search != nil && len(scope.Search.TableName) > 0 {
		return scope.Search.TableName
	} else {
		if scope.Value == nil {
			scope.Err(errors.New("can't get table name"))
			return ""
		}

		data := scope.IndirectValue()
		if data.Kind() == reflect.Slice {
			elem := data.Type().Elem()
			if elem.Kind() == reflect.Ptr {
				elem = elem.Elem()
			}
			data = reflect.New(elem).Elem()
		}

		if fm := data.MethodByName("TableName"); fm.IsValid() {
			if v := fm.Call([]reflect.Value{}); len(v) > 0 {
				if result, ok := v[0].Interface().(string); ok {
					return result
				}
			}
		}

		str := ToSnake(data.Type().Name())

		if scope.db != nil && !scope.db.parent.singularTable {
			for index, reg := range pluralMapKeys {
				if reg.MatchString(str) {
					return reg.ReplaceAllString(str, pluralMapValues[index])
				}
			}
		}

		return str
	}
}

func (scope *Scope) QuotedTableName() string {
	if scope.Search != nil && len(scope.Search.TableName) > 0 {
		return scope.Search.TableName
	} else {
		keys := strings.Split(scope.TableName(), ".")
		for i, v := range keys {
			keys[i] = scope.Quote(v)
		}
		return strings.Join(keys, ".")
	}
}

// CombinedConditionSql get combined condition sql
func (scope *Scope) CombinedConditionSql() string {
	return scope.joinsSql() + scope.whereSql() + scope.groupSql() +
		scope.havingSql() + scope.orderSql() + scope.limitSql() + scope.offsetSql()
}

func (scope *Scope) FieldByName(name string) (field *Field, ok bool) {
	var f reflect.StructField
	if scope.Value != nil {
		if scope.IndirectValue().Kind() == reflect.Struct {
			if f, ok = scope.IndirectValue().Type().FieldByName(SnakeToUpperCamel(name)); ok {
				field = scope.fieldFromStruct(f)
			}
		}
	}
	return
}

func (scope *Scope) fieldFromStruct(fieldStruct reflect.StructField) *Field {
	var field Field
	field.Name = fieldStruct.Name
	field.DBName = ToSnake(fieldStruct.Name)

	value := scope.IndirectValue().FieldByName(fieldStruct.Name)
	indirectValue := reflect.Indirect(value)
	field.Value = value.Interface()
	field.IsBlank = isBlank(value)

	// Search for primary key tag identifier
	settings := parseTagSetting(fieldStruct.Tag.Get("gorm"))
	if scope.PrimaryKey() == field.DBName {
		field.IsPrimaryKey = true
	}

	field.Tag = fieldStruct.Tag
	field.SqlTag = scope.sqlTagForField(&field)

	if !field.IsIgnored {
		// parse association
		if !indirectValue.IsValid() {
			indirectValue = reflect.New(value.Type())
		}
		typ := indirectValue.Type()
		foreignKey := SnakeToUpperCamel(settings["FOREIGNKEY"])
		associationForeignKey := SnakeToUpperCamel(settings["ASSOCIATIONFOREIGNKEY"])
		many2many := settings["MANY2MANY"]
		scopeTyp := scope.IndirectValue().Type()

		switch indirectValue.Kind() {
		case reflect.Slice:
			typ = typ.Elem()

			if typ.Kind() == reflect.Struct {
				if foreignKey == "" {
					foreignKey = scopeTyp.Name() + "Id"
				}
				if associationForeignKey == "" {
					associationForeignKey = typ.Name() + "Id"
				}

				// if not many to many, foreign key could be null
				if many2many == "" {
					if !reflect.New(typ).Elem().FieldByName(foreignKey).IsValid() {
						foreignKey = ""
					}
				}

				field.Relationship = &relationship{
					JoinTable:             many2many,
					ForeignKey:            foreignKey,
					AssociationForeignKey: associationForeignKey,
					Kind: "has_many",
				}

				if many2many != "" {
					field.Relationship.Kind = "many_to_many"
				}
			}
		case reflect.Struct:
			if !field.IsTime() && !field.IsScanner() {
				if foreignKey == "" && scope.HasColumn(field.Name+"Id") {
					field.Relationship = &relationship{ForeignKey: field.Name + "Id", Kind: "belongs_to"}
				} else if scope.HasColumn(foreignKey) {
					field.Relationship = &relationship{ForeignKey: foreignKey, Kind: "belongs_to"}
				} else {
					if foreignKey == "" {
						foreignKey = scopeTyp.Name() + "Id"
					}
					if reflect.New(typ).Elem().FieldByName(foreignKey).IsValid() {
						field.Relationship = &relationship{ForeignKey: foreignKey, Kind: "has_one"}
					}
				}
			}
		}
	}
	return &field
}

// Fields get value's fields
func (scope *Scope) Fields() (fields []*Field) {
	if scope.IndirectValue().IsValid() {
		scopeTyp := scope.IndirectValue().Type()
		for i := 0; i < scopeTyp.NumField(); i++ {
			fieldStruct := scopeTyp.Field(i)
			if !ast.IsExported(fieldStruct.Name) {
				continue
			}
			fields = append(fields, scope.fieldFromStruct(fieldStruct))
		}
	}
	return
}

// Raw set sql
func (scope *Scope) Raw(sql string) *Scope {
	scope.Sql = strings.Replace(sql, "$$", "?", -1)
	return scope
}

// Exec invoke sql
func (scope *Scope) Exec() *Scope {
	defer scope.Trace(time.Now())

	if !scope.HasError() {
		result, err := scope.DB().Exec(scope.Sql, scope.SqlVars...)
		if scope.Err(err) == nil {
			if count, err := result.RowsAffected(); err == nil {
				scope.db.RowsAffected = count
			}
		}
	}
	return scope
}

// Set set value by name
func (scope *Scope) Set(name string, value interface{}) *Scope {
	scope._values[name] = value
	return scope
}

// Get get value by name
func (scope *Scope) Get(name string) (value interface{}, ok bool) {
	value, ok = scope._values[name]
	return
}

// Trace print sql log
func (scope *Scope) Trace(t time.Time) {
	if len(scope.Sql) > 0 {
		scope.db.slog(scope.Sql, t, scope.SqlVars...)
	}
}

// Begin start a transaction
func (scope *Scope) Begin() *Scope {
	if db, ok := scope.DB().(sqlDb); ok {
		if tx, err := db.Begin(); err == nil {
			scope.db.db = interface{}(tx).(sqlCommon)
			scope.Set("gorm:started_transaction", true)
		}
	}
	return scope
}

// CommitOrRollback commit current transaction if there is no error, otherwise rollback it
func (scope *Scope) CommitOrRollback() *Scope {
	if _, ok := scope.Get("gorm:started_transaction"); ok {
		if db, ok := scope.db.db.(sqlTx); ok {
			if scope.HasError() {
				db.Rollback()
			} else {
				db.Commit()
			}
			scope.db.db = scope.db.parent.db
		}
	}
	return scope
}
<|endoftext|>


<commit_before>package usage

import (
	"sync"
	"testing"
	"time"

	"github.com/benbjohnson/clock"
	"github.com/raintank/met/helper"
	"github.com/raintank/metrictank/consolidation"
	"github.com/raintank/metrictank/defcache"
	"github.com/raintank/metrictank/iter"
	"github.com/raintank/metrictank/mdata"
	"github.com/raintank/metrictank/metricdef"
	"gopkg.in/raintank/schema.v0"
)

type FakeAggMetrics struct {
	sync.Mutex
	Metrics map[string]*FakeAggMetric
}

func NewFakeAggMetrics() *FakeAggMetrics {
	return &FakeAggMetrics{
		Metrics: make(map[string]*FakeAggMetric),
	}
}

func (f *FakeAggMetrics) Get(key string) (mdata.Metric, bool) {
	f.Lock()
	m, ok := f.Metrics[key]
	f.Unlock()
	return m, ok
}
func (f *FakeAggMetrics) GetOrCreate(key string) mdata.Metric {
	f.Lock()
	m, ok := f.Metrics[key]
	if !ok {
		m = &FakeAggMetric{key, 0, 0}
		f.Metrics[key] = m
	}
	f.Unlock()
	return m
}

type FakeAggMetric struct {
	key     string
	lastTs  uint32
	lastVal float64
}

func (f *FakeAggMetric) Add(ts uint32, val float64) {
	f.lastTs = ts
	f.lastVal = val
}

// we won't use this
func (f *FakeAggMetric) Get(from, to uint32) (uint32, []iter.Iter) {
	return 0, make([]iter.Iter, 0)
}
func (f *FakeAggMetric) GetAggregated(consolidator consolidation.Consolidator, aggSpan, from, to uint32) (uint32, []iter.Iter) {
	return 0, make([]iter.Iter, 0)
}

func idFor(org int, name string, tags []string) string {
	md := schema.MetricData{
		OrgId: org,
		Name:  name,
		Tags:  tags,
	}
	md.SetId()
	return md.Id
}

func assertLen(epoch int, aggmetrics *FakeAggMetrics, l int, t *testing.T) {
	aggmetrics.Lock()
	if len(aggmetrics.Metrics) != l {
		t.Fatalf("%d seconds in: there should be %d metrics at this point, not %d", epoch, l, len(aggmetrics.Metrics))
	}
	aggmetrics.Unlock()
}
func assert(epoch int, aggmetrics *FakeAggMetrics, org int, name string, ts uint32, val float64, t *testing.T) {
	id := idFor(org, name, []string{})
	m, ok := aggmetrics.Get(id)
	if !ok {
		t.Fatalf("%d seconds in: assert org %d name %s ts %d val %f -> metric not found", epoch, org, name, ts, val)
	}
	n := m.(*FakeAggMetric)
	if n.lastVal != val || n.lastTs != ts {
		t.Fatalf("%d seconds in: assert org %d name %s ts %d val %f -> got ts %d val %f", epoch, org, name, ts, val, n.lastTs, n.lastVal)
	}
}

func TestUsageBasic(t *testing.T) {
	mock := clock.NewMock()
	aggmetrics := NewFakeAggMetrics()
	stats, _ := helper.New(false, "", "standard", "metrictank", "")
	mdata.InitMetrics(stats)
	defCache := defcache.New(metricdef.NewDefsMockConcurrent(), stats)
	u := New(60, aggmetrics, defCache, mock)

	assertLen(0, aggmetrics, 0, t)

	u.Add(1, "foo")
	u.Add(1, "bar")
	u.Add(2, "foo")
	mock.Add(30 * time.Second)
	assertLen(30, aggmetrics, 0, t)
	mock.Add(29 * time.Second)
	assertLen(59, aggmetrics, 0, t)

	u.Add(2, "foo")
	mock.Add(time.Second)
	assertLen(60, aggmetrics, 4, t)
	assert(60, aggmetrics, 1, "metrictank.usage.numSeries", 60, 2, t)
	assert(60, aggmetrics, 1, "metrictank.usage.numPoints", 60, 2, t)
	assert(60, aggmetrics, 2, "metrictank.usage.numSeries", 60, 1, t)
	assert(60, aggmetrics, 2, "metrictank.usage.numPoints", 60, 2, t)

	u.Add(1, "foo")
	u.Add(2, "foo")
	mock.Add(60 * time.Second)

	assert(120, aggmetrics, 1, "metrictank.usage.numSeries", 120, 1, t)
	assert(120, aggmetrics, 1, "metrictank.usage.numPoints", 120, 3, t)
	assert(120, aggmetrics, 2, "metrictank.usage.numSeries", 120, 1, t)
	assert(120, aggmetrics, 2, "metrictank.usage.numPoints", 120, 3, t)

	u.Stop()
}
func TestUsageMinusOne(t *testing.T) {
	mock := clock.NewMock()
	aggmetrics := NewFakeAggMetrics()
	stats, _ := helper.New(false, "", "standard", "metrictank", "")
	mdata.InitMetrics(stats)
	defCache := defcache.New(metricdef.NewDefsMockConcurrent(), stats)
	u := New(60, aggmetrics, defCache, mock)

	assertLen(0, aggmetrics, 0, t)

	u.Add(-1, "globally-visible") // but usage only reported to org 1
	u.Add(1, "foo")
	u.Add(2, "bar")
	mock.Add(30 * time.Second)
	assertLen(30, aggmetrics, 0, t)
	mock.Add(29 * time.Second)
	assertLen(59, aggmetrics, 0, t)
	mock.Add(time.Second)
	assertLen(60, aggmetrics, 6, t)
	assert(60, aggmetrics, 1, "metrictank.usage-minus1.numSeries", 60, 1, t)
	assert(60, aggmetrics, 1, "metrictank.usage-minus1.numPoints", 60, 1, t)
	assert(60, aggmetrics, 1, "metrictank.usage.numSeries", 60, 1, t)
	assert(60, aggmetrics, 1, "metrictank.usage.numPoints", 60, 1, t)
	assert(60, aggmetrics, 2, "metrictank.usage.numSeries", 60, 1, t)
	assert(60, aggmetrics, 2, "metrictank.usage.numPoints", 60, 1, t)

	u.Stop()
}
func TestUsageWrap32(t *testing.T) {
	mock := clock.NewMock()
	aggmetrics := NewFakeAggMetrics()
	stats, _ := helper.New(false, "", "standard", "metrictank", "")
	mdata.InitMetrics(stats)
	defCache := defcache.New(metricdef.NewDefsMockConcurrent(), stats)
	u := New(60, aggmetrics, defCache, mock)

	// max uint32 is 4294967295, let's verify the proper wrapping around that
	// pretend an insert maxuint32 -900000

	assertLen(0, aggmetrics, 0, t)
	u.Add(2, "foo")
	u.set(2, "foo", 4294067295)
	mock.Add(30 * time.Second)
	assertLen(30, aggmetrics, 0, t)
	mock.Add(29 * time.Second)
	assertLen(59, aggmetrics, 0, t)
	mock.Add(time.Second)
	assertLen(60, aggmetrics, 2, t)
	assert(60, aggmetrics, 2, "metrictank.usage.numSeries", 60, 1, t)
	assert(60, aggmetrics, 2, "metrictank.usage.numPoints", 60, 4294067295, t)

	for i := 0; i < 1000001; i++ {
		u.Add(2, "foo")
	}
	mock.Add(60 * time.Second)
	assertLen(120, aggmetrics, 2, t)
	assert(120, aggmetrics, 2, "metrictank.usage.numSeries", 120, 1, t)
	assert(120, aggmetrics, 2, "metrictank.usage.numPoints", 120, 100000, t)

	u.Stop()
}
<commit_msg>this should fix #223<commit_after>package usage

import (
	"sync"
	"testing"
	"time"

	"github.com/benbjohnson/clock"
	"github.com/raintank/met/helper"
	"github.com/raintank/metrictank/consolidation"
	"github.com/raintank/metrictank/defcache"
	"github.com/raintank/metrictank/iter"
	"github.com/raintank/metrictank/mdata"
	"github.com/raintank/metrictank/metricdef"
	"gopkg.in/raintank/schema.v0"
)

type FakeAggMetrics struct {
	sync.Mutex
	Metrics map[string]*FakeAggMetric
}

func NewFakeAggMetrics() *FakeAggMetrics {
	return &FakeAggMetrics{
		Metrics: make(map[string]*FakeAggMetric),
	}
}

func (f *FakeAggMetrics) Get(key string) (mdata.Metric, bool) {
	f.Lock()
	m, ok := f.Metrics[key]
	f.Unlock()
	return m, ok
}
func (f *FakeAggMetrics) GetOrCreate(key string) mdata.Metric {
	f.Lock()
	m, ok := f.Metrics[key]
	if !ok {
		m = &FakeAggMetric{key, 0, 0}
		f.Metrics[key] = m
	}
	f.Unlock()
	return m
}

type FakeAggMetric struct {
	key     string
	lastTs  uint32
	lastVal float64
}

func (f *FakeAggMetric) Add(ts uint32, val float64) {
	f.lastTs = ts
	f.lastVal = val
}

// we won't use this
func (f *FakeAggMetric) Get(from, to uint32) (uint32, []iter.Iter) {
	return 0, make([]iter.Iter, 0)
}
func (f *FakeAggMetric) GetAggregated(consolidator consolidation.Consolidator, aggSpan, from, to uint32) (uint32, []iter.Iter) {
	return 0, make([]iter.Iter, 0)
}

func idFor(org int, name string, tags []string) string {
	md := schema.MetricData{
		OrgId: org,
		Name:  name,
		Tags:  tags,
	}
	md.SetId()
	return md.Id
}

func assertLen(epoch int, aggmetrics *FakeAggMetrics, l int, t *testing.T) {
	aggmetrics.Lock()
	if len(aggmetrics.Metrics) != l {
		t.Fatalf("%d seconds in: there should be %d metrics at this point, not %d", epoch, l, len(aggmetrics.Metrics))
	}
	aggmetrics.Unlock()
}
func assert(epoch int, aggmetrics *FakeAggMetrics, org int, name string, ts uint32, val float64, t *testing.T) {
	id := idFor(org, name, []string{})
	m, ok := aggmetrics.Get(id)
	if !ok {
		t.Fatalf("%d seconds in: assert org %d name %s ts %d val %f -> metric not found", epoch, org, name, ts, val)
	}
	n := m.(*FakeAggMetric)
	if n.lastVal != val || n.lastTs != ts {
		t.Fatalf("%d seconds in: assert org %d name %s ts %d val %f -> got ts %d val %f", epoch, org, name, ts, val, n.lastTs, n.lastVal)
	}
}

func TestUsageBasic(t *testing.T) {
	mock := clock.NewMock()
	aggmetrics := NewFakeAggMetrics()
	stats, _ := helper.New(false, "", "standard", "metrictank", "")
	mdata.InitMetrics(stats)
	defCache := defcache.New(metricdef.NewDefsMockConcurrent(), stats)
	u := New(60, aggmetrics, defCache, mock)

	assertLen(0, aggmetrics, 0, t)

	u.Add(1, "foo")
	u.Add(1, "bar")
	u.Add(2, "foo")
	mock.Add(30 * time.Second)
	assertLen(30, aggmetrics, 0, t)
	mock.Add(29 * time.Second)
	assertLen(59, aggmetrics, 0, t)

	u.Add(2, "foo")
	mock.Add(time.Second)
	assertLen(60, aggmetrics, 4, t)
	assert(60, aggmetrics, 1, "metrictank.usage.numSeries", 60, 2, t)
	assert(60, aggmetrics, 1, "metrictank.usage.numPoints", 60, 2, t)
	assert(60, aggmetrics, 2, "metrictank.usage.numSeries", 60, 1, t)
	assert(60, aggmetrics, 2, "metrictank.usage.numPoints", 60, 2, t)

	u.Add(1, "foo")
	u.Add(2, "foo")
	mock.Add(60 * time.Second)

	assert(120, aggmetrics, 1, "metrictank.usage.numSeries", 120, 1, t)
	assert(120, aggmetrics, 1, "metrictank.usage.numPoints", 120, 3, t)
	assert(120, aggmetrics, 2, "metrictank.usage.numSeries", 120, 1, t)
	assert(120, aggmetrics, 2, "metrictank.usage.numPoints", 120, 3, t)

	u.Stop()
}
func TestUsageMinusOne(t *testing.T) {
	mock := clock.NewMock()
	aggmetrics := NewFakeAggMetrics()
	stats, _ := helper.New(false, "", "standard", "metrictank", "")
	mdata.InitMetrics(stats)
	defCache := defcache.New(metricdef.NewDefsMockConcurrent(), stats)
	u := New(60, aggmetrics, defCache, mock)

	assertLen(0, aggmetrics, 0, t)

	u.Add(-1, "globally-visible") // but usage only reported to org 1
	u.Add(1, "foo")
	u.Add(2, "bar")
	mock.Add(30 * time.Second)
	assertLen(30, aggmetrics, 0, t)
	mock.Add(29 * time.Second)
	assertLen(59, aggmetrics, 0, t)
	mock.Add(time.Second)
	// not very pretty.. but an easy way to assure that the Usage Reporter
	// goroutine has some time to push the results into our fake aggmetrics
	time.Sleep(20 * time.Millisecond)
	assertLen(60, aggmetrics, 6, t)
	assert(60, aggmetrics, 1, "metrictank.usage-minus1.numSeries", 60, 1, t)
	assert(60, aggmetrics, 1, "metrictank.usage-minus1.numPoints", 60, 1, t)
	assert(60, aggmetrics, 1, "metrictank.usage.numSeries", 60, 1, t)
	assert(60, aggmetrics, 1, "metrictank.usage.numPoints", 60, 1, t)
	assert(60, aggmetrics, 2, "metrictank.usage.numSeries", 60, 1, t)
	assert(60, aggmetrics, 2, "metrictank.usage.numPoints", 60, 1, t)

	u.Stop()
}
func TestUsageWrap32(t *testing.T) {
	mock := clock.NewMock()
	aggmetrics := NewFakeAggMetrics()
	stats, _ := helper.New(false, "", "standard", "metrictank", "")
	mdata.InitMetrics(stats)
	defCache := defcache.New(metricdef.NewDefsMockConcurrent(), stats)
	u := New(60, aggmetrics, defCache, mock)

	// max uint32 is 4294967295, let's verify the proper wrapping around that
	// pretend an insert maxuint32 -900000

	assertLen(0, aggmetrics, 0, t)
	u.Add(2, "foo")
	u.set(2, "foo", 4294067295)
	mock.Add(30 * time.Second)
	assertLen(30, aggmetrics, 0, t)
	mock.Add(29 * time.Second)
	assertLen(59, aggmetrics, 0, t)
	mock.Add(time.Second)
	assertLen(60, aggmetrics, 2, t)
	assert(60, aggmetrics, 2, "metrictank.usage.numSeries", 60, 1, t)
	assert(60, aggmetrics, 2, "metrictank.usage.numPoints", 60, 4294067295, t)

	for i := 0; i < 1000001; i++ {
		u.Add(2, "foo")
	}
	mock.Add(60 * time.Second)
	assertLen(120, aggmetrics, 2, t)
	assert(120, aggmetrics, 2, "metrictank.usage.numSeries", 120, 1, t)
	assert(120, aggmetrics, 2, "metrictank.usage.numPoints", 120, 100000, t)

	u.Stop()
}
<|endoftext|>


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

package environs

import (
	"github.com/juju/juju/constraints"
	"github.com/juju/juju/environs/cloudinit"
	"github.com/juju/juju/instance"
	"github.com/juju/juju/network"
	"github.com/juju/juju/storage"
	"github.com/juju/juju/tools"
)

// StartInstanceParams holds parameters for the
// InstanceBroker.StartInstance method.
type StartInstanceParams struct {
	// Constraints is a set of constraints on
	// the kind of instance to create.
	Constraints constraints.Value

	// Tools is a list of tools that may be used
	// to start a Juju agent on the machine.
	Tools tools.List

	// MachineConfig describes the machine's configuration.
	MachineConfig *cloudinit.MachineConfig

	// Placement, if non-empty, contains an environment-specific
	// placement directive that may be used to decide how the
	// instance should be started.
	Placement string

	// DistributionGroup, if non-nil, is a function
	// that returns a slice of instance.Ids that belong
	// to the same distribution group as the machine
	// being provisioned. The InstanceBroker may use
	// this information to distribute instances for
	// high availability.
	DistributionGroup func() ([]instance.Id, error)

	// Disks is a set of parameters for disks that must be created.
	// Constraints specify the minimum and preferred values for each
	// variable. If any of the disks cannot be created, StartInstance
	// will return an error.
	Disks []storage.DiskParams
}

// StartInstanceResult holds the result of an
// InstanceBroker.StartInstance method call.
type StartInstanceResult struct {
	// Instance is an interface representing a cloud instance.
	Instance instance.Instance

	// HardwareCharacteristics represents the hardware characteristics
	// of the newly created instance.
	Hardware *instance.HardwareCharacteristics

	// NetworkInfo contains information about configured networks.
	NetworkInfo []network.Info

	// Disks contains a list of block devices created, each one
	// corresponding to the DiskParams in the same position of
	// StartInstanceParams.Disks.
	Disks []storage.BlockDevice
}

// TODO(wallyworld) - we want this in the environs/instance package but import loops
// stop that from being possible right now.
type InstanceBroker interface {
	// StartInstance asks for a new instance to be created, associated with
	// the provided config in machineConfig. The given config describes the juju
	// state for the new instance to connect to. The config MachineNonce, which must be
	// unique within an environment, is used by juju to protect against the
	// consequences of multiple instances being started with the same machine
	// id.
	StartInstance(args StartInstanceParams) (*StartInstanceResult, error)

	// StopInstances shuts down the instances with the specified IDs.
	// Unknown instance IDs are ignored, to enable idempotency.
	StopInstances(...instance.Id) error

	// AllInstances returns all instances currently known to the broker.
	AllInstances() ([]instance.Instance, error)
}
<commit_msg>Fix comment<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package environs

import (
	"github.com/juju/juju/constraints"
	"github.com/juju/juju/environs/cloudinit"
	"github.com/juju/juju/instance"
	"github.com/juju/juju/network"
	"github.com/juju/juju/storage"
	"github.com/juju/juju/tools"
)

// StartInstanceParams holds parameters for the
// InstanceBroker.StartInstance method.
type StartInstanceParams struct {
	// Constraints is a set of constraints on
	// the kind of instance to create.
	Constraints constraints.Value

	// Tools is a list of tools that may be used
	// to start a Juju agent on the machine.
	Tools tools.List

	// MachineConfig describes the machine's configuration.
	MachineConfig *cloudinit.MachineConfig

	// Placement, if non-empty, contains an environment-specific
	// placement directive that may be used to decide how the
	// instance should be started.
	Placement string

	// DistributionGroup, if non-nil, is a function
	// that returns a slice of instance.Ids that belong
	// to the same distribution group as the machine
	// being provisioned. The InstanceBroker may use
	// this information to distribute instances for
	// high availability.
	DistributionGroup func() ([]instance.Id, error)

	// Disks is a set of parameters for disks that must be created.
	// If any of the disks cannot be created, StartInstance must
	// return an error.
	Disks []storage.DiskParams
}

// StartInstanceResult holds the result of an
// InstanceBroker.StartInstance method call.
type StartInstanceResult struct {
	// Instance is an interface representing a cloud instance.
	Instance instance.Instance

	// HardwareCharacteristics represents the hardware characteristics
	// of the newly created instance.
	Hardware *instance.HardwareCharacteristics

	// NetworkInfo contains information about configured networks.
	NetworkInfo []network.Info

	// Disks contains a list of block devices created, each one
	// corresponding to the DiskParams in the same position of
	// StartInstanceParams.Disks.
	Disks []storage.BlockDevice
}

// TODO(wallyworld) - we want this in the environs/instance package but import loops
// stop that from being possible right now.
type InstanceBroker interface {
	// StartInstance asks for a new instance to be created, associated with
	// the provided config in machineConfig. The given config describes the juju
	// state for the new instance to connect to. The config MachineNonce, which must be
	// unique within an environment, is used by juju to protect against the
	// consequences of multiple instances being started with the same machine
	// id.
	StartInstance(args StartInstanceParams) (*StartInstanceResult, error)

	// StopInstances shuts down the instances with the specified IDs.
	// Unknown instance IDs are ignored, to enable idempotency.
	StopInstances(...instance.Id) error

	// AllInstances returns all instances currently known to the broker.
	AllInstances() ([]instance.Instance, error)
}
<|endoftext|>


<commit_before>package evidence

import (
	"bytes"
	"fmt"
	"reflect"
	"time"

	wire "github.com/tendermint/go-wire"
	"github.com/tendermint/tmlibs/log"

	"github.com/tendermint/tendermint/p2p"
	"github.com/tendermint/tendermint/types"
)

const (
	EvidenceChannel = byte(0x38)

	maxEvidenceMessageSize     = 1048576 // 1MB TODO make it configurable
	broadcastEvidenceIntervalS = 60      // broadcast uncommitted evidence this often
)

// EvidenceReactor handles evpool evidence broadcasting amongst peers.
type EvidenceReactor struct {
	p2p.BaseReactor
	evpool   *EvidencePool
	eventBus *types.EventBus
}

// NewEvidenceReactor returns a new EvidenceReactor with the given config and evpool.
func NewEvidenceReactor(evpool *EvidencePool) *EvidenceReactor {
	evR := &EvidenceReactor{
		evpool: evpool,
	}
	evR.BaseReactor = *p2p.NewBaseReactor("EvidenceReactor", evR)
	return evR
}

// SetLogger sets the Logger on the reactor and the underlying Evidence.
func (evR *EvidenceReactor) SetLogger(l log.Logger) {
	evR.Logger = l
	evR.evpool.SetLogger(l)
}

// OnStart implements cmn.Service
func (evR *EvidenceReactor) OnStart() error {
	if err := evR.BaseReactor.OnStart(); err != nil {
		return err
	}
	go evR.broadcastRoutine()
	return nil
}

// GetChannels implements Reactor.
// It returns the list of channels for this reactor.
func (evR *EvidenceReactor) GetChannels() []*p2p.ChannelDescriptor {
	return []*p2p.ChannelDescriptor{
		&p2p.ChannelDescriptor{
			ID:       EvidenceChannel,
			Priority: 5,
		},
	}
}

// AddPeer implements Reactor.
func (evR *EvidenceReactor) AddPeer(peer p2p.Peer) {
	// send the peer our high-priority evidence.
	// the rest will be sent by the broadcastRoutine
	evidences := evR.evpool.PriorityEvidence()
	msg := &EvidenceListMessage{evidences}
	success := peer.Send(EvidenceChannel, struct{ EvidenceMessage }{msg})
	if !success {
		// TODO: remove peer ?
	}
}

// RemovePeer implements Reactor.
func (evR *EvidenceReactor) RemovePeer(peer p2p.Peer, reason interface{}) {
	// nothing to do
}

// Receive implements Reactor.
// It adds any received evidence to the evpool.
func (evR *EvidenceReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) {
	_, msg, err := DecodeMessage(msgBytes)
	if err != nil {
		evR.Logger.Error("Error decoding message", "src", src, "chId", chID, "msg", msg, "err", err, "bytes", msgBytes)
		evR.Switch.StopPeerForError(src, err)
		return
	}
	evR.Logger.Debug("Receive", "src", src, "chId", chID, "msg", msg)

	switch msg := msg.(type) {
	case *EvidenceListMessage:
		for _, ev := range msg.Evidence {
			err := evR.evpool.AddEvidence(ev)
			if err != nil {
				evR.Logger.Info("Evidence is not valid", "evidence", msg.Evidence, "err", err)
				// TODO: punish peer
			}
		}
	default:
		evR.Logger.Error(fmt.Sprintf("Unknown message type %v", reflect.TypeOf(msg)))
	}
}

// SetEventSwitch implements events.Eventable.
func (evR *EvidenceReactor) SetEventBus(b *types.EventBus) {
	evR.eventBus = b
}

// Broadcast new evidence to all peers.
// Broadcasts must be non-blocking so routine is always available to read off EvidenceChan.
func (evR *EvidenceReactor) broadcastRoutine() {
	ticker := time.NewTicker(time.Second * broadcastEvidenceIntervalS)
	for {
		select {
		case evidence := <-evR.evpool.EvidenceChan():
			// broadcast some new evidence
			msg := &EvidenceListMessage{[]types.Evidence{evidence}}
			evR.Switch.Broadcast(EvidenceChannel, struct{ EvidenceMessage }{msg})

			// TODO: Broadcast runs asynchronously, so this should wait on the successChan
			// in another routine before marking to be proper.
			evR.evpool.evidenceStore.MarkEvidenceAsBroadcasted(evidence)
		case <-ticker.C:
			// broadcast all pending evidence
			msg := &EvidenceListMessage{evR.evpool.PendingEvidence()}
			evR.Switch.Broadcast(EvidenceChannel, struct{ EvidenceMessage }{msg})
		case <-evR.Quit():
			return
		}
	}
}

//-----------------------------------------------------------------------------
// Messages

const (
	msgTypeEvidence = byte(0x01)
)

// EvidenceMessage is a message sent or received by the EvidenceReactor.
type EvidenceMessage interface{}

var _ = wire.RegisterInterface(
	struct{ EvidenceMessage }{},
	wire.ConcreteType{&EvidenceListMessage{}, msgTypeEvidence},
)

// DecodeMessage decodes a byte-array into a EvidenceMessage.
func DecodeMessage(bz []byte) (msgType byte, msg EvidenceMessage, err error) {
	msgType = bz[0]
	n := new(int)
	r := bytes.NewReader(bz)
	msg = wire.ReadBinary(struct{ EvidenceMessage }{}, r, maxEvidenceMessageSize, n, &err).(struct{ EvidenceMessage }).EvidenceMessage
	return
}

//-------------------------------------

// EvidenceMessage contains a list of evidence.
type EvidenceListMessage struct {
	Evidence []types.Evidence
}

// String returns a string representation of the EvidenceListMessage.
func (m *EvidenceListMessage) String() string {
	return fmt.Sprintf("[EvidenceListMessage %v]", m.Evidence)
}
<commit_msg>stop peer if evidence is not valid<commit_after>package evidence

import (
	"bytes"
	"fmt"
	"reflect"
	"time"

	wire "github.com/tendermint/go-wire"
	"github.com/tendermint/tmlibs/log"

	"github.com/tendermint/tendermint/p2p"
	"github.com/tendermint/tendermint/types"
)

const (
	EvidenceChannel = byte(0x38)

	maxEvidenceMessageSize     = 1048576 // 1MB TODO make it configurable
	broadcastEvidenceIntervalS = 60      // broadcast uncommitted evidence this often
)

// EvidenceReactor handles evpool evidence broadcasting amongst peers.
type EvidenceReactor struct {
	p2p.BaseReactor
	evpool   *EvidencePool
	eventBus *types.EventBus
}

// NewEvidenceReactor returns a new EvidenceReactor with the given config and evpool.
func NewEvidenceReactor(evpool *EvidencePool) *EvidenceReactor {
	evR := &EvidenceReactor{
		evpool: evpool,
	}
	evR.BaseReactor = *p2p.NewBaseReactor("EvidenceReactor", evR)
	return evR
}

// SetLogger sets the Logger on the reactor and the underlying Evidence.
func (evR *EvidenceReactor) SetLogger(l log.Logger) {
	evR.Logger = l
	evR.evpool.SetLogger(l)
}

// OnStart implements cmn.Service
func (evR *EvidenceReactor) OnStart() error {
	if err := evR.BaseReactor.OnStart(); err != nil {
		return err
	}
	go evR.broadcastRoutine()
	return nil
}

// GetChannels implements Reactor.
// It returns the list of channels for this reactor.
func (evR *EvidenceReactor) GetChannels() []*p2p.ChannelDescriptor {
	return []*p2p.ChannelDescriptor{
		&p2p.ChannelDescriptor{
			ID:       EvidenceChannel,
			Priority: 5,
		},
	}
}

// AddPeer implements Reactor.
func (evR *EvidenceReactor) AddPeer(peer p2p.Peer) {
	// send the peer our high-priority evidence.
	// the rest will be sent by the broadcastRoutine
	evidences := evR.evpool.PriorityEvidence()
	msg := &EvidenceListMessage{evidences}
	success := peer.Send(EvidenceChannel, struct{ EvidenceMessage }{msg})
	if !success {
		// TODO: remove peer ?
	}
}

// RemovePeer implements Reactor.
func (evR *EvidenceReactor) RemovePeer(peer p2p.Peer, reason interface{}) {
	// nothing to do
}

// Receive implements Reactor.
// It adds any received evidence to the evpool.
func (evR *EvidenceReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) {
	_, msg, err := DecodeMessage(msgBytes)
	if err != nil {
		evR.Logger.Error("Error decoding message", "src", src, "chId", chID, "msg", msg, "err", err, "bytes", msgBytes)
		evR.Switch.StopPeerForError(src, err)
		return
	}
	evR.Logger.Debug("Receive", "src", src, "chId", chID, "msg", msg)

	switch msg := msg.(type) {
	case *EvidenceListMessage:
		for _, ev := range msg.Evidence {
			err := evR.evpool.AddEvidence(ev)
			if err != nil {
				evR.Logger.Info("Evidence is not valid", "evidence", msg.Evidence, "err", err)
				// punish peer
				evR.Switch.StopPeerForError(src, err)
			}
		}
	default:
		evR.Logger.Error(fmt.Sprintf("Unknown message type %v", reflect.TypeOf(msg)))
	}
}

// SetEventSwitch implements events.Eventable.
func (evR *EvidenceReactor) SetEventBus(b *types.EventBus) {
	evR.eventBus = b
}

// Broadcast new evidence to all peers.
// Broadcasts must be non-blocking so routine is always available to read off EvidenceChan.
func (evR *EvidenceReactor) broadcastRoutine() {
	ticker := time.NewTicker(time.Second * broadcastEvidenceIntervalS)
	for {
		select {
		case evidence := <-evR.evpool.EvidenceChan():
			// broadcast some new evidence
			msg := &EvidenceListMessage{[]types.Evidence{evidence}}
			evR.Switch.Broadcast(EvidenceChannel, struct{ EvidenceMessage }{msg})

			// TODO: Broadcast runs asynchronously, so this should wait on the successChan
			// in another routine before marking to be proper.
			evR.evpool.evidenceStore.MarkEvidenceAsBroadcasted(evidence)
		case <-ticker.C:
			// broadcast all pending evidence
			msg := &EvidenceListMessage{evR.evpool.PendingEvidence()}
			evR.Switch.Broadcast(EvidenceChannel, struct{ EvidenceMessage }{msg})
		case <-evR.Quit():
			return
		}
	}
}

//-----------------------------------------------------------------------------
// Messages

const (
	msgTypeEvidence = byte(0x01)
)

// EvidenceMessage is a message sent or received by the EvidenceReactor.
type EvidenceMessage interface{}

var _ = wire.RegisterInterface(
	struct{ EvidenceMessage }{},
	wire.ConcreteType{&EvidenceListMessage{}, msgTypeEvidence},
)

// DecodeMessage decodes a byte-array into a EvidenceMessage.
func DecodeMessage(bz []byte) (msgType byte, msg EvidenceMessage, err error) {
	msgType = bz[0]
	n := new(int)
	r := bytes.NewReader(bz)
	msg = wire.ReadBinary(struct{ EvidenceMessage }{}, r, maxEvidenceMessageSize, n, &err).(struct{ EvidenceMessage }).EvidenceMessage
	return
}

//-------------------------------------

// EvidenceMessage contains a list of evidence.
type EvidenceListMessage struct {
	Evidence []types.Evidence
}

// String returns a string representation of the EvidenceListMessage.
func (m *EvidenceListMessage) String() string {
	return fmt.Sprintf("[EvidenceListMessage %v]", m.Evidence)
}
<|endoftext|>


<commit_before>/*
 * Minimalist Object Storage, (C) 2015 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 api

import (
	"net/http"

	"github.com/gorilla/mux"
	"github.com/minio-io/minio/pkg/iodine"
	"github.com/minio-io/minio/pkg/storage/drivers"
	"github.com/minio-io/minio/pkg/utils/log"
)

func (server *minioAPI) isValidOp(w http.ResponseWriter, req *http.Request, acceptsContentType contentType) bool {
	vars := mux.Vars(req)
	bucket := vars["bucket"]

	bucketMetadata, err := server.driver.GetBucketMetadata(bucket)
	switch iodine.ToError(err).(type) {
	case drivers.BucketNotFound:
		{
			writeErrorResponse(w, req, NoSuchBucket, acceptsContentType, req.URL.Path)
			return false
		}
	case drivers.BucketNameInvalid:
		{
			writeErrorResponse(w, req, InvalidBucketName, acceptsContentType, req.URL.Path)
			return false
		}
	case nil:
		if stripAccessKey(req) == "" && bucketMetadata.ACL.IsPrivate() {
			writeErrorResponse(w, req, AccessDenied, acceptsContentType, req.URL.Path)
			return false
		}
		if bucketMetadata.ACL.IsPublicRead() && req.Method == "PUT" {
			writeErrorResponse(w, req, AccessDenied, acceptsContentType, req.URL.Path)
			return false
		}
	}
	return true
}

// GET Bucket (List Objects)
// -------------------------
// This implementation of the GET operation returns some or all (up to 1000)
// of the objects in a bucket. You can use the request parameters as selection
// criteria to return a subset of the objects in a bucket.
//
func (server *minioAPI) listObjectsHandler(w http.ResponseWriter, req *http.Request) {
	acceptsContentType := getContentType(req)
	if acceptsContentType == unknownContentType {
		writeErrorResponse(w, req, NotAcceptable, acceptsContentType, req.URL.Path)
		return
	}
	// verify if bucket allows this operation
	if !server.isValidOp(w, req, acceptsContentType) {
		return
	}

	resources := getBucketResources(req.URL.Query())
	if resources.Maxkeys == 0 {
		resources.Maxkeys = maxObjectList
	}

	vars := mux.Vars(req)
	bucket := vars["bucket"]

	objects, resources, err := server.driver.ListObjects(bucket, resources)
	switch err := iodine.ToError(err).(type) {
	case nil: // success
		{
			// write headers
			setCommonHeaders(w, getContentTypeString(acceptsContentType))
			w.WriteHeader(http.StatusOK)
			// write body
			response := generateObjectsListResult(bucket, objects, resources)
			encodedSuccessResponse := encodeSuccessResponse(response, acceptsContentType)
			w.Write(encodedSuccessResponse)
		}
	case drivers.ObjectNotFound:
		{
			writeErrorResponse(w, req, NoSuchKey, acceptsContentType, req.URL.Path)
		}
	case drivers.ObjectNameInvalid:
		{
			writeErrorResponse(w, req, NoSuchKey, acceptsContentType, req.URL.Path)
		}
	default:
		{
			log.Error.Println(iodine.New(err, nil))
			writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path)
		}
	}
}

// GET Service
// -----------
// This implementation of the GET operation returns a list of all buckets
// owned by the authenticated sender of the request.
func (server *minioAPI) listBucketsHandler(w http.ResponseWriter, req *http.Request) {
	acceptsContentType := getContentType(req)
	if acceptsContentType == unknownContentType {
		writeErrorResponse(w, req, NotAcceptable, acceptsContentType, req.URL.Path)
		return
	}

	buckets, err := server.driver.ListBuckets()
	// cannot fallthrough in (type) switch :(
	switch err := iodine.ToError(err).(type) {
	case nil:
		{
			response := generateBucketsListResult(buckets)
			// write headers
			setCommonHeaders(w, getContentTypeString(acceptsContentType))
			w.WriteHeader(http.StatusOK)
			// write response
			encodedSuccessResponse := encodeSuccessResponse(response, acceptsContentType)
			w.Write(encodedSuccessResponse)
		}
	default:
		{
			log.Error.Println(iodine.New(err, nil))
			writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path)
		}
	}
}

// PUT Bucket
// ----------
// This implementation of the PUT operation creates a new bucket for authenticated request
func (server *minioAPI) putBucketHandler(w http.ResponseWriter, req *http.Request) {
	acceptsContentType := getContentType(req)
	if acceptsContentType == unknownContentType {
		writeErrorResponse(w, req, NotAcceptable, acceptsContentType, req.URL.Path)
		return
	}

	// read from 'x-amz-acl'
	aclType := getACLType(req)
	if aclType == unsupportedACLType {
		writeErrorResponse(w, req, NotImplemented, acceptsContentType, req.URL.Path)
		return
	}

	vars := mux.Vars(req)
	bucket := vars["bucket"]
	err := server.driver.CreateBucket(bucket, getACLTypeString(aclType))
	switch iodine.ToError(err).(type) {
	case nil:
		{
			w.Header().Set("Server", "Minio")
			w.Header().Set("Connection", "close")
			w.WriteHeader(http.StatusOK)
		}
	case drivers.BucketNameInvalid:
		{
			writeErrorResponse(w, req, InvalidBucketName, acceptsContentType, req.URL.Path)
		}
	case drivers.BucketExists:
		{
			writeErrorResponse(w, req, BucketAlreadyExists, acceptsContentType, req.URL.Path)
		}
	default:
		{
			log.Error.Println(iodine.New(err, nil))
			writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path)
		}
	}
}

// HEAD Bucket
// ----------
// This operation is useful to determine if a bucket exists.
// The operation returns a 200 OK if the bucket exists and you
// have permission to access it. Otherwise, the operation might
// return responses such as 404 Not Found and 403 Forbidden.
func (server *minioAPI) headBucketHandler(w http.ResponseWriter, req *http.Request) {
	acceptsContentType := getContentType(req)
	if acceptsContentType == unknownContentType {
		writeErrorResponse(w, req, NotAcceptable, acceptsContentType, req.URL.Path)
		return
	}

	// verify if bucket allows this operation
	if !server.isValidOp(w, req, acceptsContentType) {
		return
	}

	// Always a success if isValidOp succeeds
	w.Header().Set("Server", "Minio")
	w.Header().Set("Connection", "close")
	w.WriteHeader(http.StatusOK)
}
<commit_msg>Disable verifying ACL until we get webcli up and running<commit_after>/*
 * Minimalist Object Storage, (C) 2015 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 api

import (
	"net/http"

	"github.com/gorilla/mux"
	"github.com/minio-io/minio/pkg/iodine"
	"github.com/minio-io/minio/pkg/storage/drivers"
	"github.com/minio-io/minio/pkg/utils/log"
)

func (server *minioAPI) isValidOp(w http.ResponseWriter, req *http.Request, acceptsContentType contentType) bool {
	vars := mux.Vars(req)
	bucket := vars["bucket"]

	bucketMetadata, err := server.driver.GetBucketMetadata(bucket)
	switch iodine.ToError(err).(type) {
	case drivers.BucketNotFound:
		{
			writeErrorResponse(w, req, NoSuchBucket, acceptsContentType, req.URL.Path)
			return false
		}
	case drivers.BucketNameInvalid:
		{
			writeErrorResponse(w, req, InvalidBucketName, acceptsContentType, req.URL.Path)
			return false
		}
	case nil:

		if stripAccessKey(req) == "" && bucketMetadata.ACL.IsPrivate() {
			return true
			// Uncomment this when we have webCli
			// writeErrorResponse(w, req, AccessDenied, acceptsContentType, req.URL.Path)
			// return false
		}
		if bucketMetadata.ACL.IsPublicRead() && req.Method == "PUT" {
			return true
			// Uncomment this when we have webCli
			// writeErrorResponse(w, req, AccessDenied, acceptsContentType, req.URL.Path)
			// return false
		}
	}
	return true
}

// GET Bucket (List Objects)
// -------------------------
// This implementation of the GET operation returns some or all (up to 1000)
// of the objects in a bucket. You can use the request parameters as selection
// criteria to return a subset of the objects in a bucket.
//
func (server *minioAPI) listObjectsHandler(w http.ResponseWriter, req *http.Request) {
	acceptsContentType := getContentType(req)
	if acceptsContentType == unknownContentType {
		writeErrorResponse(w, req, NotAcceptable, acceptsContentType, req.URL.Path)
		return
	}
	// verify if bucket allows this operation
	if !server.isValidOp(w, req, acceptsContentType) {
		return
	}

	resources := getBucketResources(req.URL.Query())
	if resources.Maxkeys == 0 {
		resources.Maxkeys = maxObjectList
	}

	vars := mux.Vars(req)
	bucket := vars["bucket"]

	objects, resources, err := server.driver.ListObjects(bucket, resources)
	switch err := iodine.ToError(err).(type) {
	case nil: // success
		{
			// write headers
			setCommonHeaders(w, getContentTypeString(acceptsContentType))
			w.WriteHeader(http.StatusOK)
			// write body
			response := generateObjectsListResult(bucket, objects, resources)
			encodedSuccessResponse := encodeSuccessResponse(response, acceptsContentType)
			w.Write(encodedSuccessResponse)
		}
	case drivers.ObjectNotFound:
		{
			writeErrorResponse(w, req, NoSuchKey, acceptsContentType, req.URL.Path)
		}
	case drivers.ObjectNameInvalid:
		{
			writeErrorResponse(w, req, NoSuchKey, acceptsContentType, req.URL.Path)
		}
	default:
		{
			log.Error.Println(iodine.New(err, nil))
			writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path)
		}
	}
}

// GET Service
// -----------
// This implementation of the GET operation returns a list of all buckets
// owned by the authenticated sender of the request.
func (server *minioAPI) listBucketsHandler(w http.ResponseWriter, req *http.Request) {
	acceptsContentType := getContentType(req)
	if acceptsContentType == unknownContentType {
		writeErrorResponse(w, req, NotAcceptable, acceptsContentType, req.URL.Path)
		return
	}

	buckets, err := server.driver.ListBuckets()
	// cannot fallthrough in (type) switch :(
	switch err := iodine.ToError(err).(type) {
	case nil:
		{
			response := generateBucketsListResult(buckets)
			// write headers
			setCommonHeaders(w, getContentTypeString(acceptsContentType))
			w.WriteHeader(http.StatusOK)
			// write response
			encodedSuccessResponse := encodeSuccessResponse(response, acceptsContentType)
			w.Write(encodedSuccessResponse)
		}
	default:
		{
			log.Error.Println(iodine.New(err, nil))
			writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path)
		}
	}
}

// PUT Bucket
// ----------
// This implementation of the PUT operation creates a new bucket for authenticated request
func (server *minioAPI) putBucketHandler(w http.ResponseWriter, req *http.Request) {
	acceptsContentType := getContentType(req)
	if acceptsContentType == unknownContentType {
		writeErrorResponse(w, req, NotAcceptable, acceptsContentType, req.URL.Path)
		return
	}

	// read from 'x-amz-acl'
	aclType := getACLType(req)
	if aclType == unsupportedACLType {
		writeErrorResponse(w, req, NotImplemented, acceptsContentType, req.URL.Path)
		return
	}

	vars := mux.Vars(req)
	bucket := vars["bucket"]
	err := server.driver.CreateBucket(bucket, getACLTypeString(aclType))
	switch iodine.ToError(err).(type) {
	case nil:
		{
			w.Header().Set("Server", "Minio")
			w.Header().Set("Connection", "close")
			w.WriteHeader(http.StatusOK)
		}
	case drivers.BucketNameInvalid:
		{
			writeErrorResponse(w, req, InvalidBucketName, acceptsContentType, req.URL.Path)
		}
	case drivers.BucketExists:
		{
			writeErrorResponse(w, req, BucketAlreadyExists, acceptsContentType, req.URL.Path)
		}
	default:
		{
			log.Error.Println(iodine.New(err, nil))
			writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path)
		}
	}
}

// HEAD Bucket
// ----------
// This operation is useful to determine if a bucket exists.
// The operation returns a 200 OK if the bucket exists and you
// have permission to access it. Otherwise, the operation might
// return responses such as 404 Not Found and 403 Forbidden.
func (server *minioAPI) headBucketHandler(w http.ResponseWriter, req *http.Request) {
	acceptsContentType := getContentType(req)
	if acceptsContentType == unknownContentType {
		writeErrorResponse(w, req, NotAcceptable, acceptsContentType, req.URL.Path)
		return
	}

	// verify if bucket allows this operation
	if !server.isValidOp(w, req, acceptsContentType) {
		return
	}

	// Always a success if isValidOp succeeds
	w.Header().Set("Server", "Minio")
	w.Header().Set("Connection", "close")
	w.WriteHeader(http.StatusOK)
}
<|endoftext|>


<commit_before>// +build windows

package archive

import (
	"fmt"
	"strings"

	"github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
)

// canonicalTarNameForPath returns platform-specific filepath
// to canonical posix-style path for tar archival. p is relative
// path.
func CanonicalTarNameForPath(p string) (string, error) {
	// windows: convert windows style relative path with backslashes
	// into forward slashes. since windows does not allow '/' or '\'
	// in file names, it is mostly safe to replace however we must
	// check just in case
	if strings.Contains(p, "/") {
		return "", fmt.Errorf("windows path contains forward slash: %s", p)
	}
	return strings.Replace(p, "\\", "/", -1), nil
}

func setHeaderForSpecialDevice(hdr *tar.Header, ta *tarAppender, name string, stat interface{}) (nlink uint32, inode uint64, err error) {
	// do nothing. no notion of Rdev, Inode, Nlink in stat on Windows
	return
}
<commit_msg>pkg/archive_windows: make use of os.PathSeparator<commit_after>// +build windows

package archive

import (
	"fmt"
	"os"
	"strings"

	"github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
)

// canonicalTarNameForPath returns platform-specific filepath
// to canonical posix-style path for tar archival. p is relative
// path.
func CanonicalTarNameForPath(p string) (string, error) {
	// windows: convert windows style relative path with backslashes
	// into forward slashes. since windows does not allow '/' or '\'
	// in file names, it is mostly safe to replace however we must
	// check just in case
	if strings.Contains(p, "/") {
		return "", fmt.Errorf("windows path contains forward slash: %s", p)
	}
	return strings.Replace(p, string(os.PathSeparator), "/", -1), nil

}

func setHeaderForSpecialDevice(hdr *tar.Header, ta *tarAppender, name string, stat interface{}) (nlink uint32, inode uint64, err error) {
	// do nothing. no notion of Rdev, Inode, Nlink in stat on Windows
	return
}
<|endoftext|>


<commit_before>/*
Copyright 2018 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 initializer

import (
	"context"
	"fmt"
	"time"

	v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/discovery"
	corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
	apiregistrationv1 "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/typed/apiregistration/v1"
	migrationv1alpha1 "sigs.k8s.io/kube-storage-version-migrator/pkg/apis/migration/v1alpha1"
	"sigs.k8s.io/kube-storage-version-migrator/pkg/clients/clientset/typed/migration/v1alpha1"
)

type initializer struct {
	discovery       *migrationDiscovery
	crdClient       apiextensionsv1.CustomResourceDefinitionInterface
	namespaceClient corev1.NamespaceInterface
	migrationClient v1alpha1.StorageVersionMigrationInterface
}

func NewInitializer(
	disocveryClient discovery.ServerResourcesInterface,
	crdClient apiextensionsv1.CustomResourceDefinitionInterface,
	apiserviceClient apiregistrationv1.APIServiceInterface,
	namespaceClient corev1.NamespaceInterface,
	migrationGetter v1alpha1.StorageVersionMigrationsGetter,
) *initializer {
	d := NewDiscovery(disocveryClient, crdClient, apiserviceClient)
	return &initializer{
		discovery:       d,
		crdClient:       crdClient,
		namespaceClient: namespaceClient,
		migrationClient: migrationGetter.StorageVersionMigrations(),
	}
}

const (
	singularCRDName = "storageversionmigration"
	pluralCRDName   = "storageversionmigrations"
	kind            = "StorageVersionMigration"
	listKind        = "StorageVersionMigrationList"
)

func migrationCRD() *v1.CustomResourceDefinition {
	return &v1.CustomResourceDefinition{
		ObjectMeta: metav1.ObjectMeta{
			Name: "storageversionmigrations.migration.k8s.io",
			Annotations: map[string]string{
				"api-approved.kubernetes.io": "https://github.com/kubernetes/community/pull/2524",
			},
		},
		Spec: v1.CustomResourceDefinitionSpec{
			Group: "migration.k8s.io",
			Names: v1.CustomResourceDefinitionNames{
				Plural:   pluralCRDName,
				Singular: singularCRDName,
				Kind:     kind,
				ListKind: listKind,
			},
			Scope: v1.ClusterScoped,
			Versions: []v1.CustomResourceDefinitionVersion{
				{
					Name:    "v1alpha1",
					Served:  true,
					Storage: true,
					Subresources: &v1.CustomResourceSubresources{
						Status: &v1.CustomResourceSubresourceStatus{},
					},
					Schema: &v1.CustomResourceValidation{
						OpenAPIV3Schema: &v1.JSONSchemaProps{
							Description: "StorageVersionMigration represents a migration of stored data to the latest storage version.",
							Type:        "object",
							Properties: map[string]v1.JSONSchemaProps{
								"apiVersion": v1.JSONSchemaProps{
									Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
									Type:        "string",
								},
								"kind": v1.JSONSchemaProps{
									Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
									Type:        "string",
								},
								"metadata": v1.JSONSchemaProps{
									Type: "object",
								},
								"spec": v1.JSONSchemaProps{
									Description: "Specification of the migration.",
									Type:        "object",
									Required: []string{
										"resource",
									},
									Properties: map[string]v1.JSONSchemaProps{
										"continueToken": v1.JSONSchemaProps{
											Description: "The token used in the list options to get the next chunk of objects to migrate. When the .status.conditions indicates the migration is \"Running\", users can use this token to check the progress of the migration.",
											Type:        "string",
										},
										"resource": v1.JSONSchemaProps{
											Description: "The resource that is being migrated. The migrator sends requests to the endpoint serving the resource. Immutable.",
											Type:        "object",
											Properties: map[string]v1.JSONSchemaProps{
												"group": v1.JSONSchemaProps{
													Description: "The name of the group.",
													Type:        "string",
												},
												"resource": v1.JSONSchemaProps{
													Description: "The name of the resource.",
													Type:        "string",
												},
												"version": v1.JSONSchemaProps{
													Description: "The name of the version.",
													Type:        "string",
												},
											},
										},
									},
								},
								"status": v1.JSONSchemaProps{
									Description: "Status of the migration.",
									Type:        "object",
									Properties: map[string]v1.JSONSchemaProps{
										"conditions": v1.JSONSchemaProps{
											Description: "The latest available observations of the migration's current state.",
											Type:        "array",
											Items: &v1.JSONSchemaPropsOrArray{
												Schema: &v1.JSONSchemaProps{
													Description: "Describes the state of a migration at a certain point.",
													Type:        "object",
													Required: []string{
														"status",
														"type",
													},
													Properties: map[string]v1.JSONSchemaProps{
														"lastUpdateTime": v1.JSONSchemaProps{
															Description: "The last time this condition was updated.",
															Type:        "string",
															Format:      "date-time",
														},
														"message": v1.JSONSchemaProps{
															Description: "A human readable message indicating details about the transition.",
															Type:        "string",
														},
														"reason": v1.JSONSchemaProps{
															Description: "The reason for the condition's last transition.",
															Type:        "string",
														},
														"status": v1.JSONSchemaProps{
															Description: "Status of the condition, one of True, False, Unknown.",
															Type:        "string",
														},
														"type": v1.JSONSchemaProps{
															Description: "Type of the condition.",
															Type:        "string",
														},
													},
												},
											},
										},
									},
								},
							},
						},
					},
				},
			},
		},
	}
}

func migrationForResource(resource schema.GroupVersionResource) *migrationv1alpha1.StorageVersionMigration {
	var name string
	if len(resource.Group) != 0 {
		name = fmt.Sprintf("%s.%s.%s-", resource.Group, resource.Version, resource.Resource)
	} else {
		name = fmt.Sprintf("%s.%s-", resource.Version, resource.Resource)
	}
	return &migrationv1alpha1.StorageVersionMigration{
		ObjectMeta: metav1.ObjectMeta{
			GenerateName: name,
		},
		Spec: migrationv1alpha1.StorageVersionMigrationSpec{
			Resource: migrationv1alpha1.GroupVersionResource{
				Group:    resource.Group,
				Version:  resource.Version,
				Resource: resource.Resource,
			},
		},
	}
}

func (init *initializer) initializeCRD(ctx context.Context) error {
	crdName := fmt.Sprintf("%s.%s", pluralCRDName, migrationv1alpha1.GroupName)
	// check if crd already exists
	_, err := init.crdClient.Get(ctx, crdName, metav1.GetOptions{})
	if err != nil && !errors.IsNotFound(err) {
		return err
	}
	if err != nil && errors.IsNotFound(err) {
		_, err := init.crdClient.Create(ctx, migrationCRD(), metav1.CreateOptions{})
		return err
	}

	// delete the crd, and wait for it's deletion
	if err := init.crdClient.Delete(ctx, crdName, metav1.DeleteOptions{}); err != nil {
		return err
	}
	err = wait.PollImmediate(500*time.Millisecond, 30*time.Second, func() (bool, error) {
		_, err := init.crdClient.Get(ctx, crdName, metav1.GetOptions{})
		if err == nil {
			return false, nil
		}
		if errors.IsNotFound(err) {
			return true, nil
		}
		return false, err
	})
	if err != nil {
		return err
	}
	_, err = init.crdClient.Create(ctx, migrationCRD(), metav1.CreateOptions{})
	return err
}

func (init *initializer) Initialize(ctx context.Context) error {
	// TODO: remove deployment code.
	if err := init.initializeCRD(ctx); err != nil {
		return err
	}

	// run discovery
	resources, err := init.discovery.FindMigratableResources(ctx)
	if err != nil {
		return err
	}

	for _, r := range resources {
		if _, err := init.migrationClient.Create(ctx, migrationForResource(r), metav1.CreateOptions{}); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>Make golang 1.16 gofmt happy<commit_after>/*
Copyright 2018 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 initializer

import (
	"context"
	"fmt"
	"time"

	v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/discovery"
	corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
	apiregistrationv1 "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/typed/apiregistration/v1"
	migrationv1alpha1 "sigs.k8s.io/kube-storage-version-migrator/pkg/apis/migration/v1alpha1"
	"sigs.k8s.io/kube-storage-version-migrator/pkg/clients/clientset/typed/migration/v1alpha1"
)

type initializer struct {
	discovery       *migrationDiscovery
	crdClient       apiextensionsv1.CustomResourceDefinitionInterface
	namespaceClient corev1.NamespaceInterface
	migrationClient v1alpha1.StorageVersionMigrationInterface
}

func NewInitializer(
	disocveryClient discovery.ServerResourcesInterface,
	crdClient apiextensionsv1.CustomResourceDefinitionInterface,
	apiserviceClient apiregistrationv1.APIServiceInterface,
	namespaceClient corev1.NamespaceInterface,
	migrationGetter v1alpha1.StorageVersionMigrationsGetter,
) *initializer {
	d := NewDiscovery(disocveryClient, crdClient, apiserviceClient)
	return &initializer{
		discovery:       d,
		crdClient:       crdClient,
		namespaceClient: namespaceClient,
		migrationClient: migrationGetter.StorageVersionMigrations(),
	}
}

const (
	singularCRDName = "storageversionmigration"
	pluralCRDName   = "storageversionmigrations"
	kind            = "StorageVersionMigration"
	listKind        = "StorageVersionMigrationList"
)

func migrationCRD() *v1.CustomResourceDefinition {
	return &v1.CustomResourceDefinition{
		ObjectMeta: metav1.ObjectMeta{
			Name: "storageversionmigrations.migration.k8s.io",
			Annotations: map[string]string{
				"api-approved.kubernetes.io": "https://github.com/kubernetes/community/pull/2524",
			},
		},
		Spec: v1.CustomResourceDefinitionSpec{
			Group: "migration.k8s.io",
			Names: v1.CustomResourceDefinitionNames{
				Plural:   pluralCRDName,
				Singular: singularCRDName,
				Kind:     kind,
				ListKind: listKind,
			},
			Scope: v1.ClusterScoped,
			Versions: []v1.CustomResourceDefinitionVersion{
				{
					Name:    "v1alpha1",
					Served:  true,
					Storage: true,
					Subresources: &v1.CustomResourceSubresources{
						Status: &v1.CustomResourceSubresourceStatus{},
					},
					Schema: &v1.CustomResourceValidation{
						OpenAPIV3Schema: &v1.JSONSchemaProps{
							Description: "StorageVersionMigration represents a migration of stored data to the latest storage version.",
							Type:        "object",
							Properties: map[string]v1.JSONSchemaProps{
								"apiVersion": {
									Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
									Type:        "string",
								},
								"kind": {
									Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
									Type:        "string",
								},
								"metadata": {
									Type: "object",
								},
								"spec": {
									Description: "Specification of the migration.",
									Type:        "object",
									Required: []string{
										"resource",
									},
									Properties: map[string]v1.JSONSchemaProps{
										"continueToken": {
											Description: "The token used in the list options to get the next chunk of objects to migrate. When the .status.conditions indicates the migration is \"Running\", users can use this token to check the progress of the migration.",
											Type:        "string",
										},
										"resource": {
											Description: "The resource that is being migrated. The migrator sends requests to the endpoint serving the resource. Immutable.",
											Type:        "object",
											Properties: map[string]v1.JSONSchemaProps{
												"group": {
													Description: "The name of the group.",
													Type:        "string",
												},
												"resource": {
													Description: "The name of the resource.",
													Type:        "string",
												},
												"version": {
													Description: "The name of the version.",
													Type:        "string",
												},
											},
										},
									},
								},
								"status": {
									Description: "Status of the migration.",
									Type:        "object",
									Properties: map[string]v1.JSONSchemaProps{
										"conditions": {
											Description: "The latest available observations of the migration's current state.",
											Type:        "array",
											Items: &v1.JSONSchemaPropsOrArray{
												Schema: &v1.JSONSchemaProps{
													Description: "Describes the state of a migration at a certain point.",
													Type:        "object",
													Required: []string{
														"status",
														"type",
													},
													Properties: map[string]v1.JSONSchemaProps{
														"lastUpdateTime": {
															Description: "The last time this condition was updated.",
															Type:        "string",
															Format:      "date-time",
														},
														"message": {
															Description: "A human readable message indicating details about the transition.",
															Type:        "string",
														},
														"reason": {
															Description: "The reason for the condition's last transition.",
															Type:        "string",
														},
														"status": {
															Description: "Status of the condition, one of True, False, Unknown.",
															Type:        "string",
														},
														"type": {
															Description: "Type of the condition.",
															Type:        "string",
														},
													},
												},
											},
										},
									},
								},
							},
						},
					},
				},
			},
		},
	}
}

func migrationForResource(resource schema.GroupVersionResource) *migrationv1alpha1.StorageVersionMigration {
	var name string
	if len(resource.Group) != 0 {
		name = fmt.Sprintf("%s.%s.%s-", resource.Group, resource.Version, resource.Resource)
	} else {
		name = fmt.Sprintf("%s.%s-", resource.Version, resource.Resource)
	}
	return &migrationv1alpha1.StorageVersionMigration{
		ObjectMeta: metav1.ObjectMeta{
			GenerateName: name,
		},
		Spec: migrationv1alpha1.StorageVersionMigrationSpec{
			Resource: migrationv1alpha1.GroupVersionResource{
				Group:    resource.Group,
				Version:  resource.Version,
				Resource: resource.Resource,
			},
		},
	}
}

func (init *initializer) initializeCRD(ctx context.Context) error {
	crdName := fmt.Sprintf("%s.%s", pluralCRDName, migrationv1alpha1.GroupName)
	// check if crd already exists
	_, err := init.crdClient.Get(ctx, crdName, metav1.GetOptions{})
	if err != nil && !errors.IsNotFound(err) {
		return err
	}
	if err != nil && errors.IsNotFound(err) {
		_, err := init.crdClient.Create(ctx, migrationCRD(), metav1.CreateOptions{})
		return err
	}

	// delete the crd, and wait for it's deletion
	if err := init.crdClient.Delete(ctx, crdName, metav1.DeleteOptions{}); err != nil {
		return err
	}
	err = wait.PollImmediate(500*time.Millisecond, 30*time.Second, func() (bool, error) {
		_, err := init.crdClient.Get(ctx, crdName, metav1.GetOptions{})
		if err == nil {
			return false, nil
		}
		if errors.IsNotFound(err) {
			return true, nil
		}
		return false, err
	})
	if err != nil {
		return err
	}
	_, err = init.crdClient.Create(ctx, migrationCRD(), metav1.CreateOptions{})
	return err
}

func (init *initializer) Initialize(ctx context.Context) error {
	// TODO: remove deployment code.
	if err := init.initializeCRD(ctx); err != nil {
		return err
	}

	// run discovery
	resources, err := init.discovery.FindMigratableResources(ctx)
	if err != nil {
		return err
	}

	for _, r := range resources {
		if _, err := init.migrationClient.Create(ctx, migrationForResource(r), metav1.CreateOptions{}); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package zmq4_test

import (
	zmq "github.com/pebbe/zmq4"

	"fmt"
	"time"
)

func rep_socket_monitor(addr string) {
	s, err := zmq.NewSocket(zmq.PAIR)
	if checkErr(err) {
		return
	}
	defer s.Close()
	err = s.Connect(addr)
	if checkErr(err) {
		return
	}
	for {
		a, b, _, err := s.RecvEvent(0)
		if checkErr(err) {
			break
		}
		fmt.Println(a, b)
		if a == zmq.EVENT_CLOSED {
			break
		}
	}
}

func Example_socket_event() {

	// REP socket
	rep, err := zmq.NewSocket(zmq.REP)
	if checkErr(err) {
		return
	}

	// REP socket monitor, all events
	err = rep.Monitor("inproc://monitor.rep", zmq.EVENT_ALL)
	if checkErr(err) {
		rep.Close()
		return
	}
	go rep_socket_monitor("inproc://monitor.rep")
	time.Sleep(time.Second)

	// Generate an event
	rep.Bind("tcp://*:9689")
	if checkErr(err) {
		rep.Close()
		return
	}

	rep.Close()

	// Allow some time for event detection
	time.Sleep(time.Second)

	fmt.Println("Done")
	// Output:
	// EVENT_LISTENING tcp://0.0.0.0:9689
	// EVENT_CLOSED tcp://0.0.0.0:9689
	// Done
}
<commit_msg>Check Bind error in test Example_socket_event<commit_after>package zmq4_test

import (
	zmq "github.com/pebbe/zmq4"

	"fmt"
	"time"
)

func rep_socket_monitor(addr string) {
	s, err := zmq.NewSocket(zmq.PAIR)
	if checkErr(err) {
		return
	}
	defer s.Close()
	err = s.Connect(addr)
	if checkErr(err) {
		return
	}
	for {
		a, b, _, err := s.RecvEvent(0)
		if checkErr(err) {
			break
		}
		fmt.Println(a, b)
		if a == zmq.EVENT_CLOSED {
			break
		}
	}
}

func Example_socket_event() {

	// REP socket
	rep, err := zmq.NewSocket(zmq.REP)
	if checkErr(err) {
		return
	}

	// REP socket monitor, all events
	err = rep.Monitor("inproc://monitor.rep", zmq.EVENT_ALL)
	if checkErr(err) {
		rep.Close()
		return
	}
	go rep_socket_monitor("inproc://monitor.rep")
	time.Sleep(time.Second)

	// Generate an event
	err = rep.Bind("tcp://*:9689")
	if checkErr(err) {
		rep.Close()
		return
	}

	rep.Close()

	// Allow some time for event detection
	time.Sleep(time.Second)

	fmt.Println("Done")
	// Output:
	// EVENT_LISTENING tcp://0.0.0.0:9689
	// EVENT_CLOSED tcp://0.0.0.0:9689
	// Done
}
<|endoftext|>


<commit_before>package cmd

const Version = "v4.2.1"
<commit_msg>version bump<commit_after>package cmd

const Version = "v4.2.2"
<|endoftext|>


<commit_before>package cmd

const Version = "3.32.2"
<commit_msg>version bump<commit_after>package cmd

const Version = "3.33.0"
<|endoftext|>


<commit_before>package utils

import (
	"testing"

	. "gopkg.in/check.v1"
)

// Launch gocheck tests
func Test(t *testing.T) {
	TestingT(t)
}
<commit_msg>Test utils<commit_after>package utils

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

	. "gopkg.in/check.v1"
)

// Launch gocheck tests
func Test(t *testing.T) {
	TestingT(t)
}

type UtilsSuite struct {
	tempfile *os.File
}

var _ = Suite(&UtilsSuite{})

func (s *UtilsSuite) SetUpSuite(c *C) {
	s.tempfile, _ = ioutil.TempFile(c.MkDir(), "aptly-test-inaccessible")
	if err := os.Chmod(s.tempfile.Name(), 0000); err != nil {
		log.Fatalln(err)
	}
}

func (s *UtilsSuite) TestDirIsAccessibleNotExist(c *C) {
	c.Check(DirIsAccessible("does/not/exist.invalid"), Equals, nil)
}

func (s *UtilsSuite) TestDirIsAccessibleNotAccessible(c *C) {
	c.Check(DirIsAccessible(s.tempfile.Name()).Error(), Equals, fmt.Errorf("'%s' is inaccessible, check access rights", s.tempfile.Name()).Error())
}
<|endoftext|>


<commit_before>// Copyright 2018 Google LLC All Rights Reserved.
//
// 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 tarball

import (
	"archive/tar"
	"bytes"
	"encoding/json"
	"io"
	"os"

	"github.com/google/go-containerregistry/name"
	"github.com/google/go-containerregistry/v1"
)

// WriteOptions are used to expose optional information to guide or
// control the image write.
type WriteOptions struct {
	// TODO(mattmoor): Whether to store things compressed?
}

// Write saves the image as the given tag in a tarball at the given path.
func Write(p string, tag name.Tag, img v1.Image, wo *WriteOptions) error {
	// Write in the compressed format.
	// This is a tarball, on-disk, with:
	// One manifest.json file at the top level containing information about several images.
	// One file for each layer, named after the layer's SHA.
	// One file for the config blob, named after its SHA.

	w, err := os.Create(p)
	if err != nil {
		return err
	}
	defer w.Close()

	tf := tar.NewWriter(w)
	defer tf.Close()

	// Write the config.
	cfgName, err := img.ConfigName()
	if err != nil {
		return err
	}
	cfgBlob, err := img.RawConfigFile()
	if err != nil {
		return err
	}
	if err := writeFile(tf, cfgName.String(), bytes.NewReader(cfgBlob), int64(len(cfgBlob))); err != nil {
		return err
	}

	// Write the layers.
	layers, err := img.Layers()
	if err != nil {
		return err
	}
	digests := make([]string, len(layers))
	for i, l := range layers {
		d, err := l.Digest()
		if err != nil {
			return err
		}

		digests[i] = d.String()
		r, err := l.Compressed()
		if err != nil {
			return err
		}
		blobSize, err := l.Size()
		if err != nil {
			return err
		}

		if err := writeFile(tf, d.String(), r, blobSize); err != nil {
			return err
		}
	}

	// Generate the tar descriptor and write it.
	td := tarDescriptor{
		singleImageTarDescriptor{
			Config:   cfgName.String(),
			RepoTags: []string{tag.String()},
			Layers:   digests,
		},
	}
	tdBytes, err := json.Marshal(td)
	if err != nil {
		return err
	}
	return writeFile(tf, "manifest.json", bytes.NewReader(tdBytes), int64(len(tdBytes)))
}

func writeFile(tf *tar.Writer, path string, r io.Reader, size int64) error {
	hdr := &tar.Header{
		Mode:     0644,
		Typeflag: tar.TypeReg,
		Size:     size,
		Name:     path,
	}
	if err := tf.WriteHeader(hdr); err != nil {
		return err
	}
	_, err := io.Copy(tf, r)
	return err
}
<commit_msg>Make layer filenames play nice with tar and gzip (#95)<commit_after>// Copyright 2018 Google LLC All Rights Reserved.
//
// 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 tarball

import (
	"archive/tar"
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"os"

	"github.com/google/go-containerregistry/name"
	"github.com/google/go-containerregistry/v1"
)

// WriteOptions are used to expose optional information to guide or
// control the image write.
type WriteOptions struct {
	// TODO(mattmoor): Whether to store things compressed?
}

// Write saves the image as the given tag in a tarball at the given path.
func Write(p string, tag name.Tag, img v1.Image, wo *WriteOptions) error {
	// Write in the compressed format.
	// This is a tarball, on-disk, with:
	// One manifest.json file at the top level containing information about several images.
	// One file for each layer, named after the layer's SHA.
	// One file for the config blob, named after its SHA.

	w, err := os.Create(p)
	if err != nil {
		return err
	}
	defer w.Close()

	tf := tar.NewWriter(w)
	defer tf.Close()

	// Write the config.
	cfgName, err := img.ConfigName()
	if err != nil {
		return err
	}
	cfgBlob, err := img.RawConfigFile()
	if err != nil {
		return err
	}
	if err := writeFile(tf, cfgName.String(), bytes.NewReader(cfgBlob), int64(len(cfgBlob))); err != nil {
		return err
	}

	// Write the layers.
	layers, err := img.Layers()
	if err != nil {
		return err
	}
	layerFiles := make([]string, len(layers))
	for i, l := range layers {
		d, err := l.Digest()
		if err != nil {
			return err
		}

		// Munge the file name to appease ancient technology.
		//
		// tar assumes anything with a colon is a remote tape drive:
		// https://www.gnu.org/software/tar/manual/html_section/tar_45.html
		// Drop the algorithm prefix, e.g. "sha256:"
		hex := d.Hex

		// gunzip expects certain file extensions:
		// https://www.gnu.org/software/gzip/manual/html_node/Overview.html
		layerFiles[i] = fmt.Sprintf("%s.tar.gz", hex)

		r, err := l.Compressed()
		if err != nil {
			return err
		}
		blobSize, err := l.Size()
		if err != nil {
			return err
		}

		if err := writeFile(tf, layerFiles[i], r, blobSize); err != nil {
			return err
		}

	}

	// Generate the tar descriptor and write it.
	td := tarDescriptor{
		singleImageTarDescriptor{
			Config:   cfgName.String(),
			RepoTags: []string{tag.String()},
			Layers:   layerFiles,
		},
	}
	tdBytes, err := json.Marshal(td)
	if err != nil {
		return err
	}
	return writeFile(tf, "manifest.json", bytes.NewReader(tdBytes), int64(len(tdBytes)))
}

func writeFile(tf *tar.Writer, path string, r io.Reader, size int64) error {
	hdr := &tar.Header{
		Mode:     0644,
		Typeflag: tar.TypeReg,
		Size:     size,
		Name:     path,
	}
	if err := tf.WriteHeader(hdr); err != nil {
		return err
	}
	_, err := io.Copy(tf, r)
	return err
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	imap_server "github.com/jordwest/imap-server"
)

func main() {
	store := imap_server.NewDummyMailstore()
	s := imap_server.NewServer(store)
	s.Transcript = os.Stdout
	s.Addr = ":10143"

	err := s.ListenAndServe()
	if err != nil {
		fmt.Printf("Error creating test connection: %s\n", err)
	}
}
<commit_msg>Rename import in dummy server #8<commit_after>package main

import (
	"fmt"
	"os"

	imap "github.com/jordwest/imap-server"
)

func main() {
	store := imap.NewDummyMailstore()
	s := imap.NewServer(store)
	s.Transcript = os.Stdout
	s.Addr = ":10143"

	err := s.ListenAndServe()
	if err != nil {
		fmt.Printf("Error creating test connection: %s\n", err)
	}
}
<|endoftext|>