<commit_before>package mapper

import (
	"github.com/rancher/norman/types"
	"github.com/rancher/norman/types/convert"
	"k8s.io/api/core/v1"
)

type EnvironmentMapper struct {
}

func (e EnvironmentMapper) FromInternal(data map[string]interface{}) {
	var env []v1.EnvVar
	var envFrom []v1.EnvFromSource

	envMap := map[string]interface{}{}
	var envFromMaps []interface{}

	if err := convert.ToObj(data["env"], &env); err == nil {
		for _, envVar := range env {
			if envVar.ValueFrom == nil {
				envMap[envVar.Name] = envVar.Value
				continue
			}

			if envVar.ValueFrom.FieldRef != nil {
				envFromMaps = append(envFromMaps, map[string]interface{}{
					"source":     "field",
					"sourceName": envVar.ValueFrom.FieldRef.FieldPath,
					"targetKey":  envVar.Name,
				})
			}
			if envVar.ValueFrom.ResourceFieldRef != nil {
				envFromMaps = append(envFromMaps, map[string]interface{}{
					"source":     "resource",
					"sourceName": envVar.ValueFrom.ResourceFieldRef.ContainerName,
					"sourceKey":  envVar.ValueFrom.ResourceFieldRef.Resource,
					"divisor":    envVar.ValueFrom.ResourceFieldRef.Divisor,
					"targetKey":  envVar.Name,
				})
			}
			if envVar.ValueFrom.ConfigMapKeyRef != nil {
				envFromMaps = append(envFromMaps, map[string]interface{}{
					"source":     "configMap",
					"sourceName": envVar.ValueFrom.ConfigMapKeyRef.Name,
					"sourceKey":  envVar.ValueFrom.ConfigMapKeyRef.Key,
					"optional":   envVar.ValueFrom.ConfigMapKeyRef.Optional,
					"targetKey":  envVar.Name,
				})
			}
			if envVar.ValueFrom.SecretKeyRef != nil {
				envFromMaps = append(envFromMaps, map[string]interface{}{
					"source":     "secret",
					"sourceName": envVar.ValueFrom.SecretKeyRef.Name,
					"sourceKey":  envVar.ValueFrom.SecretKeyRef.Key,
					"optional":   envVar.ValueFrom.SecretKeyRef.Optional,
					"targetKey":  envVar.Name,
				})
			}
		}
	}

	if err := convert.ToObj(data["envFrom"], &envFrom); err == nil {
		for _, envVar := range envFrom {
			if envVar.SecretRef != nil {
				envFromMaps = append(envFromMaps, map[string]interface{}{
					"source":     "secret",
					"sourceName": envVar.SecretRef.Name,
					"prefix":     envVar.Prefix,
					"optional":   envVar.SecretRef.Optional,
					"type":       "/v3/project/schemas/environmentFrom",
				})
			}
			if envVar.ConfigMapRef != nil {
				envFromMaps = append(envFromMaps, map[string]interface{}{
					"source":     "configMap",
					"sourceName": envVar.ConfigMapRef.Name,
					"prefix":     envVar.Prefix,
					"optional":   envVar.ConfigMapRef.Optional,
					"type":       "/v3/project/schemas/environmentFrom",
				})
			}
		}
	}

	delete(data, "env")
	delete(data, "envFrom")

	if len(envMap) > 0 {
		data["environment"] = envMap
	}
	if len(envFromMaps) > 0 {
		data["environmentFrom"] = envFromMaps
	}
}

func (e EnvironmentMapper) ToInternal(data map[string]interface{}) {
	envVar := []map[string]interface{}{}
	envVarFrom := []map[string]interface{}{}

	for key, value := range convert.ToMapInterface(data["environment"]) {
		envVar = append(envVar, map[string]interface{}{
			"name":  key,
			"value": value,
		})
	}

	for _, value := range convert.ToMapSlice(data["environmentFrom"]) {
		source := convert.ToString(value["source"])
		if source == "" {
			continue
		}

		targetKey := convert.ToString(value["targetKey"])
		if targetKey == "" {
			switch source {
			case "secret":
				envVarFrom = append(envVarFrom, map[string]interface{}{
					"prefix": value["prefix"],
					"secretRef": map[string]interface{}{
						"name":     value["sourceName"],
						"optional": value["optional"],
					},
				})
			case "configMap":
				envVarFrom = append(envVarFrom, map[string]interface{}{
					"prefix": value["prefix"],
					"configMapRef": map[string]interface{}{
						"name":     value["sourceName"],
						"optional": value["optional"],
					},
				})
			}
		} else {
			switch source {
			case "field":
				envVar = append(envVarFrom, map[string]interface{}{
					"name": targetKey,
					"valueFrom": map[string]interface{}{
						"fieldRef": map[string]interface{}{
							"fieldPath": value["sourceName"],
						},
					},
				})
			case "resource":
				envVar = append(envVarFrom, map[string]interface{}{
					"name": targetKey,
					"valueFrom": map[string]interface{}{
						"resourceFieldRef": map[string]interface{}{
							"containerName": value["sourceName"],
							"resource":      value["sourceKey"],
							"divisor":       value["divisor"],
						},
					},
				})
			case "configMap":
				envVar = append(envVarFrom, map[string]interface{}{
					"name": targetKey,
					"valueFrom": map[string]interface{}{
						"configMapKeyRef": map[string]interface{}{
							"name":     value["sourceName"],
							"key":      value["sourceKey"],
							"optional": value["optional"],
						},
					},
				})
			case "secret":
				envVar = append(envVarFrom, map[string]interface{}{
					"name": targetKey,
					"valueFrom": map[string]interface{}{
						"secretKeyRef": map[string]interface{}{
							"name":     value["sourceName"],
							"key":      value["sourceKey"],
							"optional": value["optional"],
						},
					},
				})
			}
		}
	}

	delete(data, "environment")
	delete(data, "environmentFrom")
	data["env"] = envVar
	data["envFrom"] = envVarFrom
}

func (e EnvironmentMapper) ModifySchema(schema *types.Schema, schemas *types.Schemas) error {
	delete(schema.ResourceFields, "env")
	delete(schema.ResourceFields, "envFrom")
	return nil
}
<commit_msg>vendor change<commit_after>package mapper

import (
	"github.com/rancher/norman/types"
	"github.com/rancher/norman/types/convert"
	"k8s.io/api/core/v1"
)

type EnvironmentMapper struct {
}

func (e EnvironmentMapper) FromInternal(data map[string]interface{}) {
	var env []v1.EnvVar
	var envFrom []v1.EnvFromSource

	envMap := map[string]interface{}{}
	var envFromMaps []interface{}

	if err := convert.ToObj(data["env"], &env); err == nil {
		for _, envVar := range env {
			if envVar.ValueFrom == nil {
				envMap[envVar.Name] = envVar.Value
				continue
			}

			if envVar.ValueFrom.FieldRef != nil {
				envFromMaps = append(envFromMaps, map[string]interface{}{
					"source":     "field",
					"sourceName": envVar.ValueFrom.FieldRef.FieldPath,
					"targetKey":  envVar.Name,
				})
			}
			if envVar.ValueFrom.ResourceFieldRef != nil {
				envFromMaps = append(envFromMaps, map[string]interface{}{
					"source":     "resource",
					"sourceName": envVar.ValueFrom.ResourceFieldRef.ContainerName,
					"sourceKey":  envVar.ValueFrom.ResourceFieldRef.Resource,
					"divisor":    envVar.ValueFrom.ResourceFieldRef.Divisor,
					"targetKey":  envVar.Name,
				})
			}
			if envVar.ValueFrom.ConfigMapKeyRef != nil {
				envFromMaps = append(envFromMaps, map[string]interface{}{
					"source":     "configMap",
					"sourceName": envVar.ValueFrom.ConfigMapKeyRef.Name,
					"sourceKey":  envVar.ValueFrom.ConfigMapKeyRef.Key,
					"optional":   envVar.ValueFrom.ConfigMapKeyRef.Optional,
					"targetKey":  envVar.Name,
				})
			}
			if envVar.ValueFrom.SecretKeyRef != nil {
				envFromMaps = append(envFromMaps, map[string]interface{}{
					"source":     "secret",
					"sourceName": envVar.ValueFrom.SecretKeyRef.Name,
					"sourceKey":  envVar.ValueFrom.SecretKeyRef.Key,
					"optional":   envVar.ValueFrom.SecretKeyRef.Optional,
					"targetKey":  envVar.Name,
				})
			}
		}
	}

	if err := convert.ToObj(data["envFrom"], &envFrom); err == nil {
		for _, envVar := range envFrom {
			if envVar.SecretRef != nil {
				envFromMaps = append(envFromMaps, map[string]interface{}{
					"source":     "secret",
					"sourceName": envVar.SecretRef.Name,
					"prefix":     envVar.Prefix,
					"optional":   envVar.SecretRef.Optional,
					"type":       "/v3/project/schemas/environmentFrom",
				})
			}
			if envVar.ConfigMapRef != nil {
				envFromMaps = append(envFromMaps, map[string]interface{}{
					"source":     "configMap",
					"sourceName": envVar.ConfigMapRef.Name,
					"prefix":     envVar.Prefix,
					"optional":   envVar.ConfigMapRef.Optional,
					"type":       "/v3/project/schemas/environmentFrom",
				})
			}
		}
	}

	delete(data, "env")
	delete(data, "envFrom")

	if len(envMap) > 0 {
		data["environment"] = envMap
	}
	if len(envFromMaps) > 0 {
		data["environmentFrom"] = envFromMaps
	}
}

func (e EnvironmentMapper) ToInternal(data map[string]interface{}) {
	envVar := []map[string]interface{}{}
	envVarFrom := []map[string]interface{}{}

	for key, value := range convert.ToMapInterface(data["environment"]) {
		envVar = append(envVar, map[string]interface{}{
			"name":  key,
			"value": value,
		})
	}

	for _, value := range convert.ToMapSlice(data["environmentFrom"]) {
		source := convert.ToString(value["source"])
		if source == "" {
			continue
		}

		targetKey := convert.ToString(value["targetKey"])
		sourceKey := convert.ToString(value["sourceKey"])
		if targetKey == "" && sourceKey == "" {
			switch source {
			case "secret":
				envVarFrom = append(envVarFrom, map[string]interface{}{
					"prefix": value["prefix"],
					"secretRef": map[string]interface{}{
						"name":     value["sourceName"],
						"optional": value["optional"],
					},
				})
			case "configMap":
				envVarFrom = append(envVarFrom, map[string]interface{}{
					"prefix": value["prefix"],
					"configMapRef": map[string]interface{}{
						"name":     value["sourceName"],
						"optional": value["optional"],
					},
				})
			}
		} else {
			if targetKey == "" {
				targetKey = sourceKey
			}
			switch source {
			case "field":
				envVar = append(envVar, map[string]interface{}{
					"name": targetKey,
					"valueFrom": map[string]interface{}{
						"fieldRef": map[string]interface{}{
							"fieldPath": value["sourceName"],
						},
					},
				})
			case "resource":
				envVar = append(envVar, map[string]interface{}{
					"name": targetKey,
					"valueFrom": map[string]interface{}{
						"resourceFieldRef": map[string]interface{}{
							"containerName": value["sourceName"],
							"resource":      value["sourceKey"],
							"divisor":       value["divisor"],
						},
					},
				})
			case "configMap":
				envVar = append(envVar, map[string]interface{}{
					"name": targetKey,
					"valueFrom": map[string]interface{}{
						"configMapKeyRef": map[string]interface{}{
							"name":     value["sourceName"],
							"key":      value["sourceKey"],
							"optional": value["optional"],
						},
					},
				})
			case "secret":
				envVar = append(envVar, map[string]interface{}{
					"name": targetKey,
					"valueFrom": map[string]interface{}{
						"secretKeyRef": map[string]interface{}{
							"name":     value["sourceName"],
							"key":      value["sourceKey"],
							"optional": value["optional"],
						},
					},
				})
			}
		}
	}

	delete(data, "environment")
	delete(data, "environmentFrom")
	data["env"] = envVar
	data["envFrom"] = envVarFrom
}

func (e EnvironmentMapper) ModifySchema(schema *types.Schema, schemas *types.Schemas) error {
	delete(schema.ResourceFields, "env")
	delete(schema.ResourceFields, "envFrom")
	return nil
}
<|endoftext|>


<commit_before>package constraints

import (
	"fmt"
	"math"
	"strconv"
	"strings"
)

// Value describes a user's requirements of the hardware on which units
// of a service will run. Constraints are used to choose an existing machine
// onto which a unit will be deployed, or to provision a new machine if no
// existing one satisfies the requirements.
type Value struct {

	// Arch, if not nil or empty, indicates that a machine must run the named
	// architecture.
	Arch *string `json:"arch,omitempty" yaml:"arch,omitempty"`

	// CpuCores, if not nil, indicates that a machine must have at least that
	// number of effective cores available.
	CpuCores *uint64 `json:"cpu-cores,omitempty" yaml:"cpu-cores,omitempty"`

	// CpuPower, if not nil, indicates that a machine must have at least that
	// amount of CPU power available, where 100 CpuPower is considered to be
	// equivalent to 1 Amazon ECU (or, roughly, a single 2007-era Xeon).
	CpuPower *uint64 `json:"cpu-power,omitempty" yaml:"cpu-power,omitempty"`

	// Mem, if not nil, indicates that a machine must have at least that many
	// megabytes of RAM.
	Mem *uint64 `json:"mem,omitempty" yaml:"mem,omitempty"`
}

func (c Value) String() string {
	var strs []string
	if c.Arch != nil {
		strs = append(strs, "arch="+*c.Arch)
	}
	if c.CpuCores != nil {
		strs = append(strs, "cpu-cores="+uintStr(*c.CpuCores))
	}
	if c.CpuPower != nil {
		strs = append(strs, "cpu-power="+uintStr(*c.CpuPower))
	}
	if c.Mem != nil {
		s := uintStr(*c.Mem)
		if s != "" {
			s += "M"
		}
		strs = append(strs, "mem="+s)
	}
	return strings.Join(strs, " ")
}

func uintStr(i uint64) string {
	if i == 0 {
		return ""
	}
	return fmt.Sprintf("%d", i)
}

// ParseConstraints constructs a constraint.Value from the supplied arguments,
// each of which must contain only spaces and name=value pairs. If any
// name is specified more than once, an error is returned.
func ParseConstraints(args ...string) (Value, error) {
	cons := Value{}
	for _, arg := range args {
		raws := strings.Split(strings.TrimSpace(arg), " ")
		for _, raw := range raws {
			if raw == "" {
				continue
			}
			if err := cons.setRaw(raw); err != nil {
				return Value{}, err
			}
		}
	}
	return cons, nil
}

// Constraints implements gnuflag.Value for a Constraints.
type ConstraintsValue struct {
	Target *Constraints
}

func (v ConstraintsValue) Set(s string) error {
	cons, err := ParseConstraints(s)
	if err != nil {
		return err
	}
	*v.Target = cons
	return nil
}

func (v ConstraintsValue) String() string {
	return v.Target.String()
}

// setRaw interprets a name=value string and sets the supplied value.
func (c *Value) setRaw(raw string) error {
	eq := strings.Index(raw, "=")
	if eq <= 0 {
		return fmt.Errorf("malformed constraint %q", raw)
	}
	name, str := raw[:eq], raw[eq+1:]
	var err error
	switch name {
	case "arch":
		err = c.setArch(str)
	case "cpu-cores":
		err = c.setCpuCores(str)
	case "cpu-power":
		err = c.setCpuPower(str)
	case "mem":
		err = c.setMem(str)
	default:
		return fmt.Errorf("unknown constraint %q", name)
	}
	if err != nil {
		return fmt.Errorf("bad %q constraint: %v", name, err)
	}
	return nil
}

func (c *Value) setArch(str string) error {
	if c.Arch != nil {
		return fmt.Errorf("already set")
	}
	switch str {
	case "":
	case "amd64", "i386", "arm":
	default:
		return fmt.Errorf("%q not recognized", str)
	}
	c.Arch = &str
	return nil
}

func (c *Value) setCpuCores(str string) (err error) {
	if c.CpuCores != nil {
		return fmt.Errorf("already set")
	}
	c.CpuCores, err = parseUint64(str)
	return
}

func (c *Value) setCpuPower(str string) (err error) {
	if c.CpuPower != nil {
		return fmt.Errorf("already set")
	}
	c.CpuPower, err = parseUint64(str)
	return
}

func (c *Value) setMem(str string) error {
	if c.Mem != nil {
		return fmt.Errorf("already set")
	}
	var value uint64
	if str != "" {
		mult := 1.0
		if m, ok := mbSuffixes[str[len(str)-1:]]; ok {
			str = str[:len(str)-1]
			mult = m
		}
		val, err := strconv.ParseFloat(str, 64)
		if err != nil || val < 0 {
			return fmt.Errorf("must be a non-negative float with optional M/G/T/P suffix")
		}
		val *= mult
		value = uint64(math.Ceil(val))
	}
	c.Mem = &value
	return nil
}

func parseUint64(str string) (*uint64, error) {
	var value uint64
	if str != "" {
		if val, err := strconv.Atoi(str); err != nil || val < 0 {
			return nil, fmt.Errorf("must be a non-negative integer")
		} else {
			value = uint64(val)
		}
	}
	return &value, nil
}

var mbSuffixes = map[string]float64{
	"M": 1,
	"G": 1024,
	"T": 1024 * 1024,
	"P": 1024 * 1024 * 1024,
}
<commit_msg>undo review change based on later review<commit_after>package constraints

import (
	"fmt"
	"math"
	"strconv"
	"strings"
)

// Value describes a user's requirements of the hardware on which units
// of a service will run. Constraints are used to choose an existing machine
// onto which a unit will be deployed, or to provision a new machine if no
// existing one satisfies the requirements.
type Value struct {

	// Arch, if not nil or empty, indicates that a machine must run the named
	// architecture.
	Arch *string `json:"arch,omitempty" yaml:"arch,omitempty"`

	// CpuCores, if not nil, indicates that a machine must have at least that
	// number of effective cores available.
	CpuCores *uint64 `json:"cpu-cores,omitempty" yaml:"cpu-cores,omitempty"`

	// CpuPower, if not nil, indicates that a machine must have at least that
	// amount of CPU power available, where 100 CpuPower is considered to be
	// equivalent to 1 Amazon ECU (or, roughly, a single 2007-era Xeon).
	CpuPower *uint64 `json:"cpu-power,omitempty" yaml:"cpu-power,omitempty"`

	// Mem, if not nil, indicates that a machine must have at least that many
	// megabytes of RAM.
	Mem *uint64 `json:"mem,omitempty" yaml:"mem,omitempty"`
}

// String expresses a constraints.Value in the language in which it was specified.
func (c Value) String() string {
	var strs []string
	if c.Arch != nil {
		strs = append(strs, "arch="+*c.Arch)
	}
	if c.CpuCores != nil {
		strs = append(strs, "cpu-cores="+uintStr(*c.CpuCores))
	}
	if c.CpuPower != nil {
		strs = append(strs, "cpu-power="+uintStr(*c.CpuPower))
	}
	if c.Mem != nil {
		s := uintStr(*c.Mem)
		if s != "" {
			s += "M"
		}
		strs = append(strs, "mem="+s)
	}
	return strings.Join(strs, " ")
}

func uintStr(i uint64) string {
	if i == 0 {
		return ""
	}
	return fmt.Sprintf("%d", i)
}

// ParseConstraints constructs a constraint.Value from the supplied arguments,
// each of which must contain only spaces and name=value pairs. If any
// name is specified more than once, an error is returned.
func ParseConstraints(args ...string) (Value, error) {
	cons := Value{}
	for _, arg := range args {
		raws := strings.Split(strings.TrimSpace(arg), " ")
		for _, raw := range raws {
			if raw == "" {
				continue
			}
			if err := cons.setRaw(raw); err != nil {
				return Value{}, err
			}
		}
	}
	return cons, nil
}

// Constraints implements gnuflag.Value for a Constraints.
type ConstraintsValue struct {
	Target *Constraints
}

func (v ConstraintsValue) Set(s string) error {
	cons, err := ParseConstraints(s)
	if err != nil {
		return err
	}
	*v.Target = cons
	return nil
}

func (v ConstraintsValue) String() string {
	return v.Target.String()
}

// setRaw interprets a name=value string and sets the supplied value.
func (c *Value) setRaw(raw string) error {
	eq := strings.Index(raw, "=")
	if eq <= 0 {
		return fmt.Errorf("malformed constraint %q", raw)
	}
	name, str := raw[:eq], raw[eq+1:]
	var err error
	switch name {
	case "arch":
		err = c.setArch(str)
	case "cpu-cores":
		err = c.setCpuCores(str)
	case "cpu-power":
		err = c.setCpuPower(str)
	case "mem":
		err = c.setMem(str)
	default:
		return fmt.Errorf("unknown constraint %q", name)
	}
	if err != nil {
		return fmt.Errorf("bad %q constraint: %v", name, err)
	}
	return nil
}

func (c *Value) setArch(str string) error {
	if c.Arch != nil {
		return fmt.Errorf("already set")
	}
	switch str {
	case "":
	case "amd64", "i386", "arm":
	default:
		return fmt.Errorf("%q not recognized", str)
	}
	c.Arch = &str
	return nil
}

func (c *Value) setCpuCores(str string) (err error) {
	if c.CpuCores != nil {
		return fmt.Errorf("already set")
	}
	c.CpuCores, err = parseUint64(str)
	return
}

func (c *Value) setCpuPower(str string) (err error) {
	if c.CpuPower != nil {
		return fmt.Errorf("already set")
	}
	c.CpuPower, err = parseUint64(str)
	return
}

func (c *Value) setMem(str string) error {
	if c.Mem != nil {
		return fmt.Errorf("already set")
	}
	var value uint64
	if str != "" {
		mult := 1.0
		if m, ok := mbSuffixes[str[len(str)-1:]]; ok {
			str = str[:len(str)-1]
			mult = m
		}
		val, err := strconv.ParseFloat(str, 64)
		if err != nil || val < 0 {
			return fmt.Errorf("must be a non-negative float with optional M/G/T/P suffix")
		}
		val *= mult
		value = uint64(math.Ceil(val))
	}
	c.Mem = &value
	return nil
}

func parseUint64(str string) (*uint64, error) {
	var value uint64
	if str != "" {
		if val, err := strconv.Atoi(str); err != nil || val < 0 {
			return nil, fmt.Errorf("must be a non-negative integer")
		} else {
			value = uint64(val)
		}
	}
	return &value, nil
}

var mbSuffixes = map[string]float64{
	"M": 1,
	"G": 1024,
	"T": 1024 * 1024,
	"P": 1024 * 1024 * 1024,
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package zap

import "time"

// A Field is a deferred marshaling operation used to add a key-value pair to
// a logger's context. Keys and values are appropriately escaped for the current
// encoding scheme (e.g., JSON).
type Field interface {
	addTo(encoder) error
}

// A FieldCloser closes a nested field.
type FieldCloser interface {
	CloseField()
}

// Bool constructs a Field with the given key and value.
func Bool(key string, val bool) Field {
	return boolField{key, val}
}

// Float64 constructs a Field with the given key and value. The floating-point
// value is encoded using strconv.FormatFloat's 'g' option (exponential notation
// for large exponents, grade-school notation otherwise).
func Float64(key string, val float64) Field {
	return float64Field{key, val}
}

// Int constructs a Field with the given key and value.
func Int(key string, val int) Field {
	return int64Field{key, int64(val)}
}

// Int64 constructs a Field with the given key and value.
func Int64(key string, val int64) Field {
	return int64Field{key, val}
}

// String constructs a Field with the given key and value.
func String(key string, val string) Field {
	return stringField{key, val}
}

// Time constructs a Field with the given key and value. It represents a
// time.Time as nanoseconds since epoch.
func Time(key string, val time.Time) Field {
	return timeField{key, val}
}

// Err constructs a Field that stores err.Error() under the key "error".
func Err(err error) Field {
	return stringField{"error", err.Error()}
}

// Duration constructs a Field with the given key and value. It represents
// durations as an integer number of nanoseconds.
func Duration(key string, val time.Duration) Field {
	return int64Field{key, int64(val)}
}

// Object constructs a field with the given key and zap.Marshaler. It provides a
// flexible, but still type-safe and efficient, way to add user-defined types to
// the logging context.
func Object(key string, val Marshaler) Field {
	return marshalerField{key, val}
}

// Nest takes a key and a variadic number of Fields and creates a nested
// namespace.
func Nest(key string, fields ...Field) Field {
	return nestedField{key, fields}
}

type boolField struct {
	key string
	val bool
}

func (b boolField) addTo(enc encoder) error {
	enc.AddBool(b.key, b.val)
	return nil
}

type float64Field struct {
	key string
	val float64
}

func (f float64Field) addTo(enc encoder) error {
	enc.AddFloat64(f.key, f.val)
	return nil
}

type int64Field struct {
	key string
	val int64
}

func (i int64Field) addTo(enc encoder) error {
	enc.AddInt64(i.key, i.val)
	return nil
}

type stringField struct {
	key string
	val string
}

func (s stringField) addTo(enc encoder) error {
	enc.AddString(s.key, s.val)
	return nil
}

type timeField struct {
	key string
	val time.Time
}

func (t timeField) addTo(enc encoder) error {
	enc.AddTime(t.key, t.val)
	return nil
}

type marshalerField struct {
	key string
	val Marshaler
}

func (m marshalerField) addTo(enc encoder) error {
	closer := enc.Nest(m.key)
	err := m.val.MarshalLog(enc)
	closer.CloseField()
	return err
}

type nestedField struct {
	key  string
	vals []Field
}

func (n nestedField) addTo(enc encoder) error {
	closer := enc.Nest(n.key)
	var errs multiError
	for _, f := range n.vals {
		if err := f.addTo(enc); err != nil {
			errs = append(errs, err)
		}
	}
	closer.CloseField()
	if len(errs) > 0 {
		return errs
	}
	return nil
}
<commit_msg>Replace Field interface with a simple union<commit_after>// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package zap

import (
	"fmt"
	"math"
	"time"
)

type fieldType int

// A FieldCloser closes a nested field.
type FieldCloser interface {
	CloseField()
}

const (
	unknownType fieldType = iota
	boolType
	floatType
	intType
	int64Type
	stringType
	marshalerType
)

// A Field is a deferred marshaling operation used to add a key-value pair to
// a logger's context. Keys and values are appropriately escaped for the current
// encoding scheme (e.g., JSON).
type Field struct {
	key       string
	fieldType fieldType
	ival      int64
	str       string
	obj       Marshaler
}

// Bool constructs a Field with the given key and value.
func Bool(key string, val bool) Field {
	return Field{key: key, fieldType: boolType, ival: 1}
}

// Float64 constructs a Field with the given key and value. The floating-point
// value is encoded using strconv.FormatFloat's 'g' option (exponential notation
// for large exponents, grade-school notation otherwise).
func Float64(key string, val float64) Field {
	return Field{key: key, fieldType: floatType, ival: int64(math.Float64bits(val))}
}

// Int constructs a Field with the given key and value.
func Int(key string, val int) Field {
	return Field{key: key, fieldType: intType, ival: int64(val)}
}

// Int64 constructs a Field with the given key and value.
func Int64(key string, val int64) Field {
	return Field{key: key, fieldType: int64Type, ival: val}
}

// String constructs a Field with the given key and value.
func String(key string, val string) Field {
	return Field{key: key, fieldType: stringType, str: val}
}

// Time constructs a Field with the given key and value. It represents a
// time.Time as nanoseconds since epoch.
func Time(key string, val time.Time) Field {
	return Int64(key, val.UnixNano())
}

// Err constructs a Field that stores err.Error() under the key "error".
func Err(err error) Field {
	return String("error", err.Error())
}

// Duration constructs a Field with the given key and value. It represents
// durations as an integer number of nanoseconds.
func Duration(key string, val time.Duration) Field {
	return Int64(key, int64(val))
}

// Object constructs a field with the given key and zap.Marshaler. It provides a
// flexible, but still type-safe and efficient, way to add user-defined types to
// the logging context.
func Object(key string, val Marshaler) Field {
	return Field{key: key, fieldType: marshalerType, obj: val}
}

// Nest takes a key and a variadic number of Fields and creates a nested
// namespace.
func Nest(key string, fields ...Field) Field {
	return Field{key: key, fieldType: marshalerType, obj: multiFields(fields)}
}

type multiFields []Field

func (fs multiFields) MarshalLog(kv KeyValue) error {
	for _, f := range fs {
		f.addTo(kv)
	}
	return nil
}

func (f Field) addTo(enc KeyValue) error {
	switch f.fieldType {
	case boolType:
		enc.AddBool(f.key, f.ival == 1)
	case floatType:
		enc.AddFloat64(f.key, math.Float64frombits(uint64(f.ival)))
	case intType:
		enc.AddInt(f.key, int(f.ival))
	case int64Type:
		enc.AddInt64(f.key, f.ival)
	case stringType:
		enc.AddString(f.key, f.str)
	case marshalerType:
		closer := enc.Nest(f.key)
		err := f.obj.MarshalLog(enc)
		closer.CloseField()
		return err
	default:
		panic(fmt.Sprintf("unknown field type found: %v", f))
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"math/rand"
)

type Field struct {
	width  byte
	height byte
	state  [][]int
}

//Field.state == -2 or -1 or 0 ~ 8 or 10 ~ 18
//-2: opened with mine
//-1: not open with mine
//0 ~ 8: not open and the number of mine surrounding
//10 ~ 18: open and the number of mine surrounding

const ZERO byte = 48

func NewField(width, height, mineNum byte) *Field {
	field := &Field{width, height, [][]int{}}
	field.state = make([][]int, height+2)

	var Combination [][2]byte
	Combination = make([][2]byte, width*height)
	for i := 0; i < int(height)+2; i++ {
		field.state[i] = make([]int, width+2)
	}
	for i := 0; i < int(height); i++ {
		for j := 0; j < int(width); j++ {
			Combination[i*int(height)+j][0] = byte(i + 1)
			Combination[i*int(height)+j][1] = byte(j + 1)
		}
	}

	// set mine
	var pos [][2]byte = make([][2]byte, mineNum)
	for i := 0; i < int(mineNum); i++ {
		idx := rand.Intn(int(width*height) - i)
		pos[i] = Combination[idx]
		Combination = append(Combination[:idx], Combination[idx+1:]...)
		// set surround
		field.state[pos[i][0]-1][pos[i][1]-1] += 1
		field.state[pos[i][0]-1][pos[i][1]] += 1
		field.state[pos[i][0]-1][pos[i][1]+1] += 1
		field.state[pos[i][0]][pos[i][1]-1] += 1
		field.state[pos[i][0]][pos[i][1]+1] += 1
		field.state[pos[i][0]+1][pos[i][1]-1] += 1
		field.state[pos[i][0]+1][pos[i][1]] += 1
		field.state[pos[i][0]+1][pos[i][1]+1] += 1
	}
	for i := 0; i < int(mineNum); i++ {
		// put mine
		field.state[pos[i][0]][pos[i][1]] = -1
	}

	return field
}

func (self *Field) RefreshField() {

}

func (self *Field) Open(row, column byte) {
	self.state[row][column] += 10
}

func (self *Field) AllOpen() {
	var r, c byte
	for r = 1; r < self.height+1; r++ {
		for c = 1; c < self.width+1; c++ {
			if self.state[r][c] <= -1 {
				self.state[r][c] -= 1
			} else if self.state[r][c] <= 8 {
				self.Open(r, c)
			}
		}
	}
}

func (self *Field) RecursiveOpen(row, column byte) {
	self.Open(row, column)
	if row == 0 || row == self.height+1 || column == 0 || column == self.width+1 {
		return
	}
	if 0 <= self.state[row-1][column-1] && self.state[row-1][column-1] <= 8 {
		if self.state[row-1][column-1] == 0 {
			self.RecursiveOpen(row-1, column-1)
		} else {
			self.Open(row-1, column-1)
		}
	}
	if 0 <= self.state[row-1][column] && self.state[row-1][column] <= 8 {
		if self.state[row-1][column] == 0 {
			self.RecursiveOpen(row-1, column)
		} else {
			self.Open(row-1, column)
		}
	}
	if 0 <= self.state[row-1][column+1] && self.state[row-1][column+1] <= 8 {
		if self.state[row-1][column+1] == 0 {
			self.RecursiveOpen(row-1, column+1)
		} else {
			self.Open(row-1, column+1)
		}
	}
	if 0 <= self.state[row][column-1] && self.state[row][column-1] <= 8 {
		if self.state[row][column-1] == 0 {
			self.RecursiveOpen(row, column-1)
		} else {
			self.Open(row, column-1)
		}
	}
	if 0 <= self.state[row][column+1] && self.state[row][column+1] <= 8 {
		if self.state[row][column+1] == 0 {
			self.RecursiveOpen(row, column+1)
		} else {
			self.Open(row, column+1)
		}
	}
	if 0 <= self.state[row+1][column-1] && self.state[row+1][column-1] <= 8 {
		if self.state[row+1][column-1] == 0 {
			self.RecursiveOpen(row+1, column-1)
		} else {
			self.Open(row+1, column-1)
		}
	}
	if 0 <= self.state[row+1][column] && self.state[row+1][column] <= 8 {
		if self.state[row+1][column] == 0 {
			self.RecursiveOpen(row+1, column)
		} else {
			self.Open(row+1, column)
		}
	}
	if 0 <= self.state[row+1][column+1] && self.state[row+1][column+1] <= 8 {
		if self.state[row+1][column+1] == 0 {
			self.RecursiveOpen(row+1, column+1)
		} else {
			self.Open(row+1, column+1)
		}
	}
}

func (self *Field) Choose(row, column byte) {
	row += 1
	column += 1
	if 0 == self.state[row][column] {
		self.RecursiveOpen(row, column)
	} else if 0 < self.state[row][column] && self.state[row][column] <= 8 {
		self.Open(row, column)
	} else if self.state[row][column] == -1 {
		self.AllOpen() // game over
	}
}

func (self *Field) FieldString() (out string) {
	header := "  "
	for c := 0; c < int(self.width); c++ {
		header += fmt.Sprintf(" %d  ", c+1)
	}

	field := fmt.Sprintf("%s\n", header)
	for r := 1; r < int(self.height)+1; r++ {
		field += fmt.Sprintf("%d ", r)
		for c := 1; c < int(self.width)+1; c++ {
			if -1 <= self.state[r][c] && self.state[r][c] <= 8 {
				field += "[ ]"
			} else if self.state[r][c] == 10 {
				field += "___"
			} else if 10 < self.state[r][c] {
				field += fmt.Sprintf("_%d_", self.state[r][c]-10)
			} else if self.state[r][c] == -2 {
				field += "_*_"
			}
			field += " "
		}
		if r < int(self.height) {
			field += "\n"
		}
	}
	return fmt.Sprintf("%s", field)
}

func InputLoop(field *Field) {
	var input string
	var pos [][]byte
	for {
		fmt.Scanln(&input)
		in := []byte(input)
		pos = bytes.Split(in, []byte(","))
		if len(pos) != 2 {
			fmt.Println("2 values should be input")
			continue
		}
		field.Choose(pos[0][0]-ZERO-1, pos[1][0]-ZERO-1)
		fmt.Printf("\r%s", field.FieldString())
	}
}

func main() {
	field := NewField(8, 8, 6)
	fmt.Printf("\r%s", field.FieldString())
	InputLoop(field)
}
<commit_msg>implement before gaming setting<commit_after>package main

import (
	"bytes"
	"fmt"
	"math/rand"
)

type Field struct {
	width  byte
	height byte
	state  [][]int
}

//Field.state == -2 or -1 or 0 ~ 8 or 10 ~ 18
//-2: opened with mine
//-1: not open with mine
//0 ~ 8: not open and the number of mine surrounding
//10 ~ 18: open and the number of mine surrounding

const ZERO byte = 48

func NewField(width, height, mineNum byte) *Field {
	field := &Field{width, height, [][]int{}}
	field.state = make([][]int, height+2)

	var Combination [][2]byte
	Combination = make([][2]byte, width*height)
	for i := 0; i < int(height)+2; i++ {
		field.state[i] = make([]int, width+2)
	}
	for i := 0; i < int(height); i++ {
		for j := 0; j < int(width); j++ {
			Combination[i*int(height)+j][0] = byte(i + 1)
			Combination[i*int(height)+j][1] = byte(j + 1)
		}
	}

	// set mine
	var pos [][2]byte = make([][2]byte, mineNum)
	for i := 0; i < int(mineNum); i++ {
		idx := rand.Intn(int(width*height) - i)
		pos[i] = Combination[idx]
		Combination = append(Combination[:idx], Combination[idx+1:]...)
		// set surround
		field.state[pos[i][0]-1][pos[i][1]-1] += 1
		field.state[pos[i][0]-1][pos[i][1]] += 1
		field.state[pos[i][0]-1][pos[i][1]+1] += 1
		field.state[pos[i][0]][pos[i][1]-1] += 1
		field.state[pos[i][0]][pos[i][1]+1] += 1
		field.state[pos[i][0]+1][pos[i][1]-1] += 1
		field.state[pos[i][0]+1][pos[i][1]] += 1
		field.state[pos[i][0]+1][pos[i][1]+1] += 1
	}
	for i := 0; i < int(mineNum); i++ {
		// put mine
		field.state[pos[i][0]][pos[i][1]] = -1
	}

	return field
}

func (self *Field) RefreshField() {

}

func (self *Field) Open(row, column byte) {
	self.state[row][column] += 10
}

func (self *Field) AllOpen() {
	var r, c byte
	for r = 1; r < self.height+1; r++ {
		for c = 1; c < self.width+1; c++ {
			if self.state[r][c] <= -1 {
				self.state[r][c] -= 1
			} else if self.state[r][c] <= 8 {
				self.Open(r, c)
			}
		}
	}
}

func (self *Field) RecursiveOpen(row, column byte) {
	self.Open(row, column)
	if row == 0 || row == self.height+1 || column == 0 || column == self.width+1 {
		return
	}
	if 0 <= self.state[row-1][column-1] && self.state[row-1][column-1] <= 8 {
		if self.state[row-1][column-1] == 0 {
			self.RecursiveOpen(row-1, column-1)
		} else {
			self.Open(row-1, column-1)
		}
	}
	if 0 <= self.state[row-1][column] && self.state[row-1][column] <= 8 {
		if self.state[row-1][column] == 0 {
			self.RecursiveOpen(row-1, column)
		} else {
			self.Open(row-1, column)
		}
	}
	if 0 <= self.state[row-1][column+1] && self.state[row-1][column+1] <= 8 {
		if self.state[row-1][column+1] == 0 {
			self.RecursiveOpen(row-1, column+1)
		} else {
			self.Open(row-1, column+1)
		}
	}
	if 0 <= self.state[row][column-1] && self.state[row][column-1] <= 8 {
		if self.state[row][column-1] == 0 {
			self.RecursiveOpen(row, column-1)
		} else {
			self.Open(row, column-1)
		}
	}
	if 0 <= self.state[row][column+1] && self.state[row][column+1] <= 8 {
		if self.state[row][column+1] == 0 {
			self.RecursiveOpen(row, column+1)
		} else {
			self.Open(row, column+1)
		}
	}
	if 0 <= self.state[row+1][column-1] && self.state[row+1][column-1] <= 8 {
		if self.state[row+1][column-1] == 0 {
			self.RecursiveOpen(row+1, column-1)
		} else {
			self.Open(row+1, column-1)
		}
	}
	if 0 <= self.state[row+1][column] && self.state[row+1][column] <= 8 {
		if self.state[row+1][column] == 0 {
			self.RecursiveOpen(row+1, column)
		} else {
			self.Open(row+1, column)
		}
	}
	if 0 <= self.state[row+1][column+1] && self.state[row+1][column+1] <= 8 {
		if self.state[row+1][column+1] == 0 {
			self.RecursiveOpen(row+1, column+1)
		} else {
			self.Open(row+1, column+1)
		}
	}
}

func (self *Field) Choose(row, column byte) {
	row += 1
	column += 1
	if 0 == self.state[row][column] {
		self.RecursiveOpen(row, column)
	} else if 0 < self.state[row][column] && self.state[row][column] <= 8 {
		self.Open(row, column)
	} else if self.state[row][column] == -1 {
		self.AllOpen() // game over
	}
}

func (self *Field) FieldString() (out string) {
	header := "  "
	for c := 0; c < int(self.width); c++ {
		header += fmt.Sprintf(" %d  ", c+1)
	}

	field := fmt.Sprintf("%s\n", header)
	for r := 1; r < int(self.height)+1; r++ {
		field += fmt.Sprintf("%d ", r)
		for c := 1; c < int(self.width)+1; c++ {
			if -1 <= self.state[r][c] && self.state[r][c] <= 8 {
				field += "[ ]"
			} else if self.state[r][c] == 10 {
				field += "___"
			} else if 10 < self.state[r][c] {
				field += fmt.Sprintf("_%d_", self.state[r][c]-10)
			} else if self.state[r][c] == -2 {
				field += "_*_"
			}
			field += " "
		}
		if r < int(self.height) {
			field += "\n"
		}
	}
	return fmt.Sprintf("%s", field)
}

func InputLoop(field *Field) {
	var input string
	var pos [][]byte
	for {
		fmt.Printf("\r%s", field.FieldString())
		fmt.Scanln(&input)
		in := []byte(input)
		pos = bytes.Split(in, []byte(","))
		if len(pos) != 2 {
			fmt.Println("2 values should be input")
			continue
		}
		field.Choose(pos[0][0]-ZERO-1, pos[1][0]-ZERO-1)
	}
}

func PlayGame() {
	var input string
	var field *Field
set:
	fmt.Printf("Input width, height, (num of mine) (e.g : 8,8(,9))\n>> ")
	fmt.Scanln(&input)
	in := []byte(input)
	pos := bytes.Split(in, []byte(","))
	if len(pos) == 3 {
		field = NewField(pos[0][0]-ZERO, pos[1][0]-ZERO, pos[2][0]-ZERO)
	} else if len(pos) == 2 {
		fmt.Println("The number of mine is set to 25% automatically")
		p := byte((pos[0][0] - ZERO) * (pos[1][0] - ZERO) / 4)
		field = NewField(pos[0][0]-ZERO, pos[1][0]-ZERO, p)
	} else {
		fmt.Println("Please input 3 numerical value")
		goto set
	}
	InputLoop(field)
}

func main() {
	PlayGame()
}
<|endoftext|>


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

package kvm

import (
	"fmt"

	"launchpad.net/juju-core/container"
	"launchpad.net/juju-core/log"
)

type kvmContainer struct {
	factory *containerFactory
	name    string
	started *bool
}

var _ Container = (*kvmContainer)(nil)

func (c *kvmContainer) Name() string {
	return c.name
}

func (c *kvmContainer) Start(
	series string,
	arch string,
	userDataFile string,
	network *container.NetworkConfig,
) error {
	// TODO: handle memory, cpu, disk etc.
	logger.Debugf("Synchronise images for %s %s", series, arch)
	if err := SyncImages(series, arch); err != nil {
		return err
	}
	bridge := ""
	if network != nil {
		if network.NetworkType == container.BridgeNetwork {
			bridge = network.Device
		} else {
			return log.LoggedErrorf(logger, "Non-bridge network devices not yet supported")
		}
	}
	logger.Debugf("Create the machine %s", c.name)
	if err := CreateMachine(CreateMachineParams{
		Hostname:      c.name,
		Series:        series,
		Arch:          arch,
		UserData:      userDataFile,
		NetworkBridge: bridge,
	}); err != nil {
		return err
	}

	logger.Debugf("Set machine %s to autostart", c.name)
	return AutostartMachine(c.name)
}

func (c *kvmContainer) Stop() error {
	if c.IsRunning() {
		// Make started state unknown again.
		c.started = nil
		logger.Debugf("Stop %s", c.name)
		return DestroyMachine(c.name)
	}
	logger.Debugf("%s is already stopped", c.name)
	return nil
}

func (c *kvmContainer) IsRunning() bool {
	if c.started != nil {
		return *c.started
	}
	machines, err := ListMachines()
	if err != nil {
		return false
	}
	c.started = isRunning(machines[c.name])
	return *c.started
}

func (c *kvmContainer) String() string {
	return fmt.Sprintf("<KVM container %v>", *c)
}
<commit_msg>Review comment tweaks.<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package kvm

import (
	"fmt"

	"launchpad.net/juju-core/container"
	"launchpad.net/juju-core/log"
)

type kvmContainer struct {
	factory *containerFactory
	name    string
	// started is a three state boolean, true, false, or unknown
	// this allows for checking when we don't know, but using a
	// value if we already know it (like in the list situation).
	started *bool
}

var _ Container = (*kvmContainer)(nil)

func (c *kvmContainer) Name() string {
	return c.name
}

func (c *kvmContainer) Start(
	series string,
	arch string,
	userDataFile string,
	network *container.NetworkConfig,
) error {
	// TODO: handle memory, cpu, disk etc.
	logger.Debugf("Synchronise images for %s %s", series, arch)
	if err := SyncImages(series, arch); err != nil {
		return err
	}
	var bridge string
	if network != nil {
		if network.NetworkType == container.BridgeNetwork {
			bridge = network.Device
		} else {
			return log.LoggedErrorf(logger, "Non-bridge network devices not yet supported")
		}
	}
	logger.Debugf("Create the machine %s", c.name)
	if err := CreateMachine(CreateMachineParams{
		Hostname:      c.name,
		Series:        series,
		Arch:          arch,
		UserData:      userDataFile,
		NetworkBridge: bridge,
	}); err != nil {
		return err
	}

	logger.Debugf("Set machine %s to autostart", c.name)
	return AutostartMachine(c.name)
}

func (c *kvmContainer) Stop() error {
	if !c.IsRunning() {
		logger.Debugf("%s is already stopped", c.name)
		return nil
	}
	// Make started state unknown again.
	c.started = nil
	logger.Debugf("Stop %s", c.name)
	return DestroyMachine(c.name)
}

func (c *kvmContainer) IsRunning() bool {
	if c.started != nil {
		return *c.started
	}
	machines, err := ListMachines()
	if err != nil {
		return false
	}
	c.started = isRunning(machines[c.name])
	return *c.started
}

func (c *kvmContainer) String() string {
	return fmt.Sprintf("<KVM container %v>", *c)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	//"crypto/tls"
	"errors"
	"flag"
	"fmt"
	"github.com/prometheus/client_golang/prometheus"
	//"gopkg.in/ldap.v2"
	"gopkg.in/yaml.v2"
	//"io"
	"io/ioutil"
	"log"
	//"net"
	"net/http"
	"os"
	"os/exec"
	"regexp"
	//"strconv"
	"strings"
	//"sync"
	//"time"
)

// describes the network config and the mechanism for user auth.
// While the contents of the certificaes are public, we want to
// restrict generation to authenticated users
type baseConfig struct {
	Http_Address      string
	TLS_Cert_Filename string
	TLS_Key_Filename  string
	UserAuth          string
	SSH_CA_Filename   string
}

type LdapConfig struct {
	BindPattern   string
	LDAPTargetURL string
}

type AppConfigFile struct {
	Base baseConfig
	//	Ldap   LdapConfig
}

var (
	configFilename = flag.String("config", "config.yml", "The filename of the configuration")
	debug          = flag.Bool("debug", false, "Enable debug messages to console")
)

func getUserPubKey(username string) (string, error) {
	cmd := exec.Command("/usr/bin/sss_ssh_authorizedkeys", username)
	cmd.Stdin = strings.NewReader("some input")
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		//log.Fatal(err)
		return "", err
	}
	log.Printf("Pub key: %s\n", out.String())
	return out.String(), nil
}

// gen_user_cert a username and key, returns a short lived cert for that user
func gen_cert_internal(username string, userPubKey string, users_ca_filename string, host_identity string) (string, error) {

	//Convert userKey into temp file
	content := []byte(userPubKey)
	tmpfile, err := ioutil.TempFile("/tmp/", "userkey")
	if err != nil {
		log.Fatal(err)
	}
	defer tmpfile.Close()
	defer os.Remove(tmpfile.Name()) // clean up

	if _, err := tmpfile.Write(content); err != nil {
		log.Fatal(err)
	}

	keyIdentity := host_identity + "_" + username

	cmd := exec.Command("ssh-keygen", "-s", users_ca_filename, "-I", keyIdentity, "-n", username, "-V", "+1d", tmpfile.Name())
	cmd.Stdin = strings.NewReader("\n")
	var out bytes.Buffer
	cmd.Stdout = &out

	var cmderr bytes.Buffer
	cmd.Stderr = &cmderr
	err = cmd.Run()
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("stdout: %q\n", out.String())
	log.Printf("stderr: %q\n", cmderr.String())

	//Signed user key /tmp/userkey322296953-cert.pub: id "foo" serial 0 for bar valid from 2016-12-05T21:38:00 to 2016-12-06T19:39:45
	re := regexp.MustCompile("^Signed user key ([^:]+):")
	match := re.FindStringSubmatch(cmderr.String())
	if len(match) != 2 {
		log.Printf("badmatch; %v\n", match)
		err := errors.New("cannot find signed key name, re find failure")
		return "", err
	}
	outFilename := match[1]
	log.Printf("outfilename: %v\n", outFilename)
	defer os.Remove(outFilename)

	fileBytes, err := ioutil.ReadFile(outFilename)
	if err != nil {
		return "", err
	}

	return string(fileBytes[:]), nil
}

func getHostIdentity() (string, error) {
	return os.Hostname()
}

func genUserCert(userName string, users_ca_filename string) (string, error) {

	userPubKey, err := getUserPubKey(userName)
	if err != nil {
		log.Println(err)
		return "", err
	}

	hostIdentity, err := getHostIdentity()
	if err != nil {
		log.Println(err)
		return "", err
	}
	cert, err := gen_cert_internal(userName, userPubKey, users_ca_filename, hostIdentity)
	if err != nil {
		log.Fatal(err)
	}
	return cert, err
}

func exitsAndCanRead(fileName string, description string) error {
	if _, err := os.Stat(fileName); os.IsNotExist(err) {
		err = errors.New("mising " + description + " file")
		return err
	}
	_, err := ioutil.ReadFile(fileName)
	if err != nil {
		//panic(err)
		err = errors.New("cannot read " + description + "file")
		return err
	}
	return nil
}

func loadVerifyConfigFile(configFilename string) (AppConfigFile, error) {
	var config AppConfigFile
	if _, err := os.Stat(configFilename); os.IsNotExist(err) {
		//log.Printf("Missing config file\n")
		err = errors.New("mising config file failure")
		return config, err
	}
	source, err := ioutil.ReadFile(configFilename)
	if err != nil {
		//panic(err)
		err = errors.New("cannot read config file")
		return config, err
	}
	err = yaml.Unmarshal(source, &config)
	if err != nil {
		err = errors.New("Cannot parse config file")
		return config, err
	}

	//verify config
	err = exitsAndCanRead(config.Base.SSH_CA_Filename, "ssh CA File")
	if err != nil {
		return config, err
	}
	err = exitsAndCanRead(config.Base.TLS_Cert_Filename, "http cert file")
	if err != nil {
		return config, err
	}
	err = exitsAndCanRead(config.Base.TLS_Key_Filename, "http key file")
	if err != nil {
		return config, err
	}

	return config, nil
}

func checkUserPassword(username string, password string, config AppConfigFile) (bool, error) {
	if username == "user" && password == "pass" {
		return true, nil
	}
	return false, nil
}

func writeUnauthorizedResponse(w http.ResponseWriter) {
	w.Header().Set("WWW-Authenticate", `Basic realm="User Credentials"`)
	w.WriteHeader(401)
	w.Write([]byte("401 Unauthorized\n"))
}

// Inspired by http://stackoverflow.com/questions/21936332/idiomatic-way-of-requiring-http-basic-auth-in-go
func checkAuth(w http.ResponseWriter, r *http.Request, config AppConfigFile) (string, error) {
	//For now just check http basic
	user, pass, ok := r.BasicAuth()
	if !ok {
		writeUnauthorizedResponse(w)
		err := errors.New("Invalid or no auth header")
		return "", err
	}
	valid, err := checkUserPassword(user, pass, config)
	if err != nil {
		w.WriteHeader(500)
		w.Write([]byte("400 Internal Error\n"))
		return "", err
	}
	if !valid {
		writeUnauthorizedResponse(w)
		err := errors.New("Invalid Credentials")
		return "", err
	}
	return user, nil
	//return pair[0] == "user" && pair[1] == "pass"

}

const CERTGEN_PATH = "/certgen/"

func (config AppConfigFile) certGenHandler(w http.ResponseWriter, r *http.Request) {
	_, err := checkAuth(w, r, config)
	if err != nil {
		log.Printf("%v", err)

		return
	}

	targetUser := r.URL.Path[len(CERTGEN_PATH):]
	//fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
	//fmt.Fprintf(w, "Hi there, I love %s!", targetUser)
	cert, err := genUserCert(targetUser, config.Base.SSH_CA_Filename)
	if err != nil {
		http.NotFound(w, r)
	}
	fmt.Fprintf(w, "%s", cert)
}

func main() {
	flag.Parse()

	config, err := loadVerifyConfigFile(*configFilename)
	if err != nil {
		panic(err)
	}
	cert, err := genUserCert("camilo_viecco1", config.Base.SSH_CA_Filename)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("cert=%s", cert)
	// Expose the registered metrics via HTTP.
	http.Handle("/metrics", prometheus.Handler())
	//http.HandleFunc(CERTGEN_PATH, certGenHandler)
	http.HandleFunc(CERTGEN_PATH, config.certGenHandler)
	err = http.ListenAndServeTLS(
		config.Base.Http_Address,
		config.Base.TLS_Cert_Filename,
		config.Base.TLS_Key_Filename,
		nil)
	if err != nil {
		panic(err)
	}
}
<commit_msg>adding ldap check and test for requestor being the same<commit_after>package main

import (
	"bytes"
	"crypto/tls"
	"errors"
	"flag"
	"fmt"
	"github.com/prometheus/client_golang/prometheus"
	"gopkg.in/ldap.v2"
	"gopkg.in/yaml.v2"
	//"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"regexp"
	//"strconv"
	"strings"
	//"sync"
	"time"
)

// describes the network config and the mechanism for user auth.
// While the contents of the certificaes are public, we want to
// restrict generation to authenticated users
type baseConfig struct {
	Http_Address      string
	TLS_Cert_Filename string
	TLS_Key_Filename  string
	UserAuth          string
	SSH_CA_Filename   string
}

type LdapConfig struct {
	Bind_Pattern     string
	LDAP_Target_URLs string
}

type AppConfigFile struct {
	Base baseConfig
	Ldap LdapConfig
}

var (
	configFilename = flag.String("config", "config.yml", "The filename of the configuration")
	debug          = flag.Bool("debug", false, "Enable debug messages to console")
)

func getUserPubKey(username string) (string, error) {
	cmd := exec.Command("/usr/bin/sss_ssh_authorizedkeys", username)
	cmd.Stdin = strings.NewReader("some input")
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		//log.Fatal(err)
		return "", err
	}
	log.Printf("Pub key: %s\n", out.String())
	return out.String(), nil
}

// gen_user_cert a username and key, returns a short lived cert for that user
func gen_cert_internal(username string, userPubKey string, users_ca_filename string, host_identity string) (string, error) {

	//Convert userKey into temp file
	content := []byte(userPubKey)
	tmpfile, err := ioutil.TempFile("/tmp/", "userkey")
	if err != nil {
		log.Fatal(err)
	}
	defer tmpfile.Close()
	defer os.Remove(tmpfile.Name()) // clean up

	if _, err := tmpfile.Write(content); err != nil {
		log.Fatal(err)
	}

	keyIdentity := host_identity + "_" + username

	cmd := exec.Command("ssh-keygen", "-s", users_ca_filename, "-I", keyIdentity, "-n", username, "-V", "+1d", tmpfile.Name())
	cmd.Stdin = strings.NewReader("\n")
	var out bytes.Buffer
	cmd.Stdout = &out

	var cmderr bytes.Buffer
	cmd.Stderr = &cmderr
	err = cmd.Run()
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("stdout: %q\n", out.String())
	log.Printf("stderr: %q\n", cmderr.String())

	//Signed user key /tmp/userkey322296953-cert.pub: id "foo" serial 0 for bar valid from 2016-12-05T21:38:00 to 2016-12-06T19:39:45
	re := regexp.MustCompile("^Signed user key ([^:]+):")
	match := re.FindStringSubmatch(cmderr.String())
	if len(match) != 2 {
		log.Printf("badmatch; %v\n", match)
		err := errors.New("cannot find signed key name, re find failure")
		return "", err
	}
	outFilename := match[1]
	log.Printf("outfilename: %v\n", outFilename)
	defer os.Remove(outFilename)

	fileBytes, err := ioutil.ReadFile(outFilename)
	if err != nil {
		return "", err
	}

	return string(fileBytes[:]), nil
}

func getHostIdentity() (string, error) {
	return os.Hostname()
}

func genUserCert(userName string, users_ca_filename string) (string, error) {

	userPubKey, err := getUserPubKey(userName)
	if err != nil {
		log.Println(err)
		return "", err
	}

	hostIdentity, err := getHostIdentity()
	if err != nil {
		log.Println(err)
		return "", err
	}
	cert, err := gen_cert_internal(userName, userPubKey, users_ca_filename, hostIdentity)
	if err != nil {
		log.Fatal(err)
	}
	return cert, err
}

func exitsAndCanRead(fileName string, description string) error {
	if _, err := os.Stat(fileName); os.IsNotExist(err) {
		err = errors.New("mising " + description + " file")
		return err
	}
	_, err := ioutil.ReadFile(fileName)
	if err != nil {
		//panic(err)
		err = errors.New("cannot read " + description + "file")
		return err
	}
	return nil
}

func loadVerifyConfigFile(configFilename string) (AppConfigFile, error) {
	var config AppConfigFile
	if _, err := os.Stat(configFilename); os.IsNotExist(err) {
		//log.Printf("Missing config file\n")
		err = errors.New("mising config file failure")
		return config, err
	}
	source, err := ioutil.ReadFile(configFilename)
	if err != nil {
		//panic(err)
		err = errors.New("cannot read config file")
		return config, err
	}
	err = yaml.Unmarshal(source, &config)
	if err != nil {
		err = errors.New("Cannot parse config file")
		return config, err
	}

	//verify config
	err = exitsAndCanRead(config.Base.SSH_CA_Filename, "ssh CA File")
	if err != nil {
		return config, err
	}
	err = exitsAndCanRead(config.Base.TLS_Cert_Filename, "http cert file")
	if err != nil {
		return config, err
	}
	err = exitsAndCanRead(config.Base.TLS_Key_Filename, "http key file")
	if err != nil {
		return config, err
	}

	return config, nil
}

func checkLDAPUserPassword(u url.URL, bindDN string, bindPassword string, timeoutSecs uint) (bool, error) {
	if u.Scheme != "ldaps" {
		err := errors.New("Invalid ldap scheme (we only support ldaps")
		return false, err
	}
	//connectionAttemptCounter.WithLabelValues(server).Add(1)
	//hostnamePort := server + ":636"
	serverPort := strings.Split(u.Host, ":")
	port := "636"
	if len(serverPort) == 2 {
		port = serverPort[1]
	}
	server := serverPort[0]
	hostnamePort := server + ":" + port
	if *debug {
		log.Println("about to connect to:" + hostnamePort)
	}

	timeout := time.Duration(time.Duration(timeoutSecs) * time.Second)
	start := time.Now()
	tlsConn, err := tls.DialWithDialer(&net.Dialer{Timeout: timeout}, "tcp", hostnamePort, &tls.Config{ServerName: server})
	if err != nil {
		errorTime := time.Since(start).Seconds() * 1000
		log.Printf("connction failure for:%s (%s)(time(ms)=%v)", server, err.Error(), errorTime)
		return false, err
	}

	// we dont close the tls connection directly  close defer to the new ldap connection
	conn := ldap.NewConn(tlsConn, true)
	defer conn.Close()

	connectionTime := time.Since(start).Seconds() * 1000
	if *debug {
		log.Printf("connectionDelay = %v connecting to: %v:", connectionTime, hostnamePort)
	}

	conn.SetTimeout(timeout)
	conn.Start()
	err = conn.Bind(bindDN, bindPassword)
	if err != nil {
		log.Printf("Bind failure for server %s (%s)", server, err.Error())
		return false, err
	}
	return true, nil

}

func parseLDAPURL(ldapUrl string) (*url.URL, error) {
	u, err := url.Parse(ldapUrl)
	if err != nil {
		return nil, err
	}
	if u.Scheme != "ldaps" {
		err := errors.New("Invalid ldap scheme (we only support ldaps")
		return nil, err
	}
	//extract port if any... and if NIL then set it to 636
	return u, nil
}

func convertToBindDN(username string, bind_pattern string) string {
	return fmt.Sprintf(bind_pattern, username)
}

func checkUserPassword(username string, password string, config AppConfigFile) (bool, error) {
	const timeoutSecs = 3
	bindDN := convertToBindDN(username, config.Ldap.Bind_Pattern)
	for _, ldapUrl := range strings.Split(config.Ldap.LDAP_Target_URLs, ",") {
		u, err := parseLDAPURL(ldapUrl)
		if err != nil {
			log.Printf("Failed to parse %s", ldapUrl)
			continue
		}
		vaild, err := checkLDAPUserPassword(*u, bindDN, password, timeoutSecs)
		if err != nil {
			//log.Printf("Failed to parse %s", ldapUrl)
			continue
		}
		// the ldap exchange was successful (user might be invaid)
		return vaild, nil

	}
	return false, nil
}

func writeUnauthorizedResponse(w http.ResponseWriter) {
	w.Header().Set("WWW-Authenticate", `Basic realm="User Credentials"`)
	w.WriteHeader(401)
	w.Write([]byte("401 Unauthorized\n"))
}

func writeForbiddenResponse(w http.ResponseWriter) {
	w.Header().Set("WWW-Authenticate", `Basic realm="User Credentials"`)
	w.WriteHeader(403)
	w.Write([]byte("403 Forbidden\n"))
}

// Inspired by http://stackoverflow.com/questions/21936332/idiomatic-way-of-requiring-http-basic-auth-in-go
func checkAuth(w http.ResponseWriter, r *http.Request, config AppConfigFile) (string, error) {
	//For now just check http basic
	user, pass, ok := r.BasicAuth()
	if !ok {
		writeUnauthorizedResponse(w)
		err := errors.New("check_Auth, Invalid or no auth header")
		return "", err
	}
	valid, err := checkUserPassword(user, pass, config)
	if err != nil {
		w.WriteHeader(500)
		w.Write([]byte("400 Internal Error\n"))
		return "", err
	}
	if !valid {
		writeUnauthorizedResponse(w)
		err := errors.New("Invalid Credentials")
		return "", err
	}
	return user, nil

}

const CERTGEN_PATH = "/certgen/"

func (config AppConfigFile) certGenHandler(w http.ResponseWriter, r *http.Request) {
	authUser, err := checkAuth(w, r, config)
	if err != nil {
		log.Printf("%v", err)

		return
	}

	targetUser := r.URL.Path[len(CERTGEN_PATH):]
	if authUser != targetUser {
		writeForbiddenResponse(w)
		log.Printf("User %s asking for creds for %s", authUser, targetUser)
		return
	}

	//fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
	//fmt.Fprintf(w, "Hi there, I love %s!", targetUser)
	cert, err := genUserCert(targetUser, config.Base.SSH_CA_Filename)
	if err != nil {
		http.NotFound(w, r)
	}
	fmt.Fprintf(w, "%s", cert)
}

func main() {
	flag.Parse()

	config, err := loadVerifyConfigFile(*configFilename)
	if err != nil {
		panic(err)
	}
	cert, err := genUserCert("camilo_viecco1", config.Base.SSH_CA_Filename)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("cert=%s", cert)
	// Expose the registered metrics via HTTP.
	http.Handle("/metrics", prometheus.Handler())
	//http.HandleFunc(CERTGEN_PATH, certGenHandler)
	http.HandleFunc(CERTGEN_PATH, config.certGenHandler)
	err = http.ListenAndServeTLS(
		config.Base.Http_Address,
		config.Base.TLS_Cert_Filename,
		config.Base.TLS_Key_Filename,
		nil)
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"github.com/grafana/grafana/pkg/log"
	"github.com/raintank/raintank-metric/metric_tank/consolidation"
	"math"
	"runtime"
	"sync"
	"time"
)

// doRecover is the handler that turns panics into returns from the top level of getTarget.
func doRecover(errp *error) {
	e := recover()
	if e != nil {
		if _, ok := e.(runtime.Error); ok {
			panic(e)
		}
		if err, ok := e.(error); ok {
			*errp = err
		} else if errStr, ok := e.(string); ok {
			*errp = errors.New(errStr)
		} else {
			*errp = fmt.Errorf("%v", e)
		}
	}
	return
}

// fix assures all points are nicely aligned (quantized) and padded with nulls in case there's gaps in data
// graphite does this quantization before storing, we may want to do that as well at some point
// note: values are quantized to the right because we can't lie about the future:
// e.g. if interval is 10 and we have a point at 8 or at 2, it will be quantized to 10, we should never move
// values to earlier in time.
func fix(in []Point, from, to, interval uint32) []Point {
	out := make([]Point, 0, len(in))

	// first point should be the first point at or after from that divides by interval
	start := from
	remain := from % interval
	if remain != 0 {
		start = from + interval - remain
	}

	// last point should be the last value that divides by interval lower than to (because to is always exclusive)
	lastPoint := (to - 1) - ((to - 1) % interval)

	for t, i := start, 0; t <= lastPoint; t += interval {

		// input is out of values. add a null
		if i >= len(in) {
			out = append(out, Point{math.NaN(), t})
			continue
		}

		p := in[i]
		if p.Ts == t {
			// point has perfect ts, use it and move on to next point
			out = append(out, p)
			i++
		} else if p.Ts > t {
			// point is too recent, append a null and reconsider same point for next slot
			out = append(out, Point{math.NaN(), t})
		} else if p.Ts > t-interval && p.Ts < t {
			// point is a bit older, so it's good enough, just quantize the ts, and move on to next point for next round
			out = append(out, Point{p.Val, t})
			i++
		} else if p.Ts <= t-interval {
			// point is too old. advance until we find a point that is recent enough, and then go through the considerations again,
			// if those considerations are any of the above ones.
			// if the last point would end up in this branch again, discard it as well.
			for p.Ts <= t-interval && i < len(in)-1 {
				i++
				p = in[i]
			}
			if p.Ts <= t-interval {
				i++
			}
			t -= interval
		}

	}

	return out
}

func divide(pointsA, pointsB []Point) []Point {
	if len(pointsA) != len(pointsB) {
		panic(fmt.Errorf("divide of a series with len %d by a series with len %d", len(pointsA), len(pointsB)))
	}
	out := make([]Point, len(pointsA))
	for i, a := range pointsA {
		b := pointsB[i]
		out[i] = Point{a.Val / b.Val, a.Ts}
	}
	return out
}

func consolidate(in []Point, aggNum uint32, consolidator consolidation.Consolidator) []Point {
	num := int(aggNum)
	aggFunc := consolidation.GetAggFunc(consolidator)
	buf := make([]float64, num)
	bufpos := -1
	outLen := len(in) / num
	if len(in)%num != 0 {
		outLen += 1
	}
	points := make([]Point, 0, outLen)
	for inpos, p := range in {
		bufpos = inpos % num
		buf[bufpos] = p.Val
		if bufpos == num-1 {
			points = append(points, Point{aggFunc(buf), p.Ts})
		}

	}
	if bufpos != -1 && bufpos < num-1 {
		// we have an incomplete buf of some points that didn't get aggregated yet
		// we must also aggregate it and add it, and the timestamp of this point must be what it would have been
		// if the buf would have been complete, i.e. points in the consolidation output should be evenly spaced.
		// obviously we can only figure out the interval if we have at least 2 points
		var lastTs uint32
		if len(in) == 1 {
			lastTs = in[0].Ts
		} else {
			interval := in[len(in)-1].Ts - in[len(in)-2].Ts
			// len 10, num 3 -> 3*4 values supposedly -> "in[11].Ts" -> in[9].Ts + 2*interval
			lastTs = in[len(in)-1].Ts + uint32(num-len(in)%num)*interval
		}
		points = append(points, Point{aggFunc(buf[:bufpos+1]), lastTs})
	}
	return points
}

// returns how many points should be aggregated together so that you end up with as many points as possible,
// but never more than maxPoints
func aggEvery(numPoints, maxPoints uint32) uint32 {
	return (numPoints + maxPoints - 1) / maxPoints
}

// error is the error of the first failing target request
func getTargets(store Store, reqs []Req) ([]Series, error) {
	seriesChan := make(chan Series, len(reqs))
	errorsChan := make(chan error, len(reqs))
	// TODO: abort pending requests on error, maybe use context, maybe timeouts too
	wg := sync.WaitGroup{}
	wg.Add(len(reqs))
	for _, req := range reqs {
		go func(wg *sync.WaitGroup, req Req) {
			pre := time.Now()
			points, interval, err := getTarget(store, req)
			if err != nil {
				errorsChan <- err
			} else {
				getTargetDuration.Value(time.Now().Sub(pre))
				seriesChan <- Series{
					Target:     req.target,
					Datapoints: points,
					Interval:   interval,
				}
			}
			wg.Done()
		}(&wg, req)
	}
	go func() {
		wg.Wait()
		close(seriesChan)
		close(errorsChan)
	}()
	out := make([]Series, 0, len(reqs))
	var err error
	for series := range seriesChan {
		out = append(out, series)
	}
	for e := range errorsChan {
		err = e
		break
	}
	return out, err

}

func getTarget(store Store, req Req) (points []Point, interval uint32, err error) {
	defer doRecover(&err)

	readConsolidated := req.archive != 0   // do we need to read from a downsampled series?
	runtimeConsolidation := req.aggNum > 1 // do we need to compress any points at runtime?

	log.Debug("getTarget()         %s", req)
	log.Debug("type   interval   points")

	if runtimeConsolidation {
		log.Debug("runtimeConsolidation: true. agg factor: %d -> output interval: %d", req.aggNum, req.outInterval)
	} else {
		log.Debug("runtimeConsolidation: false. output interval: %d", req.outInterval)
	}

	if !readConsolidated && !runtimeConsolidation {
		return fix(
			getSeries(store, req.key, consolidation.None, 0, req.from, req.to),
			req.from,
			req.to,
			req.archInterval,
		), req.outInterval, nil
	} else if !readConsolidated && runtimeConsolidation {
		return consolidate(
			fix(
				getSeries(store, req.key, consolidation.None, 0, req.from, req.to),
				req.from,
				req.to,
				req.archInterval,
			),
			req.aggNum,
			req.consolidator), req.outInterval, nil
	} else if readConsolidated && !runtimeConsolidation {
		if req.consolidator == consolidation.Avg {
			return divide(
				fix(
					getSeries(store, req.key, consolidation.Sum, req.archInterval, req.from, req.to),
					req.from,
					req.to,
					req.archInterval,
				),
				fix(
					getSeries(store, req.key, consolidation.Cnt, req.archInterval, req.from, req.to),
					req.from,
					req.to,
					req.archInterval,
				),
			), req.outInterval, nil
		} else {
			return fix(
				getSeries(store, req.key, req.consolidator, req.archInterval, req.from, req.to),
				req.from,
				req.to,
				req.archInterval,
			), req.outInterval, nil
		}
	} else {
		// readConsolidated && runtimeConsolidation
		if req.consolidator == consolidation.Avg {
			return divide(
				consolidate(
					fix(
						getSeries(store, req.key, consolidation.Sum, req.archInterval, req.from, req.to),
						req.from,
						req.to,
						req.archInterval,
					),
					req.aggNum,
					consolidation.Sum),
				consolidate(
					fix(
						getSeries(store, req.key, consolidation.Cnt, req.archInterval, req.from, req.to),
						req.from,
						req.to,
						req.archInterval,
					),
					req.aggNum,
					consolidation.Sum),
			), req.outInterval, nil
		} else {
			return consolidate(
				fix(
					getSeries(store, req.key, req.consolidator, req.archInterval, req.from, req.to),
					req.from,
					req.to,
					req.archInterval,
				),
				req.aggNum, req.consolidator), req.outInterval, nil
		}
	}
}

func logLoad(typ, key string, from, to uint32) {
	log.Debug("load from %-6s %-20s %d - %d (%s - %s) span:%ds", typ, key, from, to, TS(from), TS(to), to-from-1)
}

func aggMetricKey(key, archive string, aggSpan uint32) string {
	return fmt.Sprintf("%s_%s_%d", key, archive, aggSpan)
}

// getSeries just gets the needed raw iters from mem and/or cassandra, based on from/to
// it can query for data within aggregated archives, by using fn min/max/sum/cnt and providing the matching agg span.
func getSeries(store Store, key string, consolidator consolidation.Consolidator, aggSpan, fromUnix, toUnix uint32) []Point {
	iters := make([]Iter, 0)
	memIters := make([]Iter, 0)
	oldest := toUnix
	if metric, ok := metrics.Get(key); ok {
		if consolidator != consolidation.None {
			logLoad("memory", aggMetricKey(key, consolidator.Archive(), aggSpan), fromUnix, toUnix)
			oldest, memIters = metric.GetAggregated(consolidator, aggSpan, fromUnix, toUnix)
		} else {
			logLoad("memory", key, fromUnix, toUnix)
			oldest, memIters = metric.Get(fromUnix, toUnix)
		}
	}
	if oldest > fromUnix {
		reqSpanBoth.Value(int64(toUnix - fromUnix))
		if consolidator != consolidation.None {
			key = aggMetricKey(key, consolidator.Archive(), aggSpan)
		}
		// if oldest < to -> search until oldest, we already have the rest from mem
		// if to < oldest -> no need to search until oldest, only search until to
		until := min(oldest, toUnix)
		logLoad("cassan", key, fromUnix, until)
		storeIters, err := store.Search(key, fromUnix, until)
		if err != nil {
			panic(err)
		}
		iters = append(iters, storeIters...)
	} else {
		reqSpanMem.Value(int64(toUnix - fromUnix))
	}
	pre := time.Now()
	iters = append(iters, memIters...)

	points := make([]Point, 0)
	for _, iter := range iters {
		total := 0
		good := 0
		for iter.Next() {
			total += 1
			ts, val := iter.Values()
			if ts >= fromUnix && ts < toUnix {
				good += 1
				points = append(points, Point{val, ts})
			}
		}
		log.Debug("getSeries: iter %s  values good/total %d/%d", iter.cmt, good, total)
	}
	itersToPointsDuration.Value(time.Now().Sub(pre))
	return points
}
<commit_msg>fix aggEvery edge case which fixes alerting edge case<commit_after>package main

import (
	"errors"
	"fmt"
	"github.com/grafana/grafana/pkg/log"
	"github.com/raintank/raintank-metric/metric_tank/consolidation"
	"math"
	"runtime"
	"sync"
	"time"
)

// doRecover is the handler that turns panics into returns from the top level of getTarget.
func doRecover(errp *error) {
	e := recover()
	if e != nil {
		if _, ok := e.(runtime.Error); ok {
			panic(e)
		}
		if err, ok := e.(error); ok {
			*errp = err
		} else if errStr, ok := e.(string); ok {
			*errp = errors.New(errStr)
		} else {
			*errp = fmt.Errorf("%v", e)
		}
	}
	return
}

// fix assures all points are nicely aligned (quantized) and padded with nulls in case there's gaps in data
// graphite does this quantization before storing, we may want to do that as well at some point
// note: values are quantized to the right because we can't lie about the future:
// e.g. if interval is 10 and we have a point at 8 or at 2, it will be quantized to 10, we should never move
// values to earlier in time.
func fix(in []Point, from, to, interval uint32) []Point {
	out := make([]Point, 0, len(in))

	// first point should be the first point at or after from that divides by interval
	start := from
	remain := from % interval
	if remain != 0 {
		start = from + interval - remain
	}

	// last point should be the last value that divides by interval lower than to (because to is always exclusive)
	lastPoint := (to - 1) - ((to - 1) % interval)

	for t, i := start, 0; t <= lastPoint; t += interval {

		// input is out of values. add a null
		if i >= len(in) {
			out = append(out, Point{math.NaN(), t})
			continue
		}

		p := in[i]
		if p.Ts == t {
			// point has perfect ts, use it and move on to next point
			out = append(out, p)
			i++
		} else if p.Ts > t {
			// point is too recent, append a null and reconsider same point for next slot
			out = append(out, Point{math.NaN(), t})
		} else if p.Ts > t-interval && p.Ts < t {
			// point is a bit older, so it's good enough, just quantize the ts, and move on to next point for next round
			out = append(out, Point{p.Val, t})
			i++
		} else if p.Ts <= t-interval {
			// point is too old. advance until we find a point that is recent enough, and then go through the considerations again,
			// if those considerations are any of the above ones.
			// if the last point would end up in this branch again, discard it as well.
			for p.Ts <= t-interval && i < len(in)-1 {
				i++
				p = in[i]
			}
			if p.Ts <= t-interval {
				i++
			}
			t -= interval
		}

	}

	return out
}

func divide(pointsA, pointsB []Point) []Point {
	if len(pointsA) != len(pointsB) {
		panic(fmt.Errorf("divide of a series with len %d by a series with len %d", len(pointsA), len(pointsB)))
	}
	out := make([]Point, len(pointsA))
	for i, a := range pointsA {
		b := pointsB[i]
		out[i] = Point{a.Val / b.Val, a.Ts}
	}
	return out
}

func consolidate(in []Point, aggNum uint32, consolidator consolidation.Consolidator) []Point {
	num := int(aggNum)
	aggFunc := consolidation.GetAggFunc(consolidator)
	buf := make([]float64, num)
	bufpos := -1
	outLen := len(in) / num
	if len(in)%num != 0 {
		outLen += 1
	}
	points := make([]Point, 0, outLen)
	for inpos, p := range in {
		bufpos = inpos % num
		buf[bufpos] = p.Val
		if bufpos == num-1 {
			points = append(points, Point{aggFunc(buf), p.Ts})
		}

	}
	if bufpos != -1 && bufpos < num-1 {
		// we have an incomplete buf of some points that didn't get aggregated yet
		// we must also aggregate it and add it, and the timestamp of this point must be what it would have been
		// if the buf would have been complete, i.e. points in the consolidation output should be evenly spaced.
		// obviously we can only figure out the interval if we have at least 2 points
		var lastTs uint32
		if len(in) == 1 {
			lastTs = in[0].Ts
		} else {
			interval := in[len(in)-1].Ts - in[len(in)-2].Ts
			// len 10, num 3 -> 3*4 values supposedly -> "in[11].Ts" -> in[9].Ts + 2*interval
			lastTs = in[len(in)-1].Ts + uint32(num-len(in)%num)*interval
		}
		points = append(points, Point{aggFunc(buf[:bufpos+1]), lastTs})
	}
	return points
}

// returns how many points should be aggregated together so that you end up with as many points as possible,
// but never more than maxPoints
func aggEvery(numPoints, maxPoints uint32) uint32 {
	if numPoints == 0 {
		return 1
	}
	return (numPoints + maxPoints - 1) / maxPoints
}

// error is the error of the first failing target request
func getTargets(store Store, reqs []Req) ([]Series, error) {
	seriesChan := make(chan Series, len(reqs))
	errorsChan := make(chan error, len(reqs))
	// TODO: abort pending requests on error, maybe use context, maybe timeouts too
	wg := sync.WaitGroup{}
	wg.Add(len(reqs))
	for _, req := range reqs {
		go func(wg *sync.WaitGroup, req Req) {
			pre := time.Now()
			points, interval, err := getTarget(store, req)
			if err != nil {
				errorsChan <- err
			} else {
				getTargetDuration.Value(time.Now().Sub(pre))
				seriesChan <- Series{
					Target:     req.target,
					Datapoints: points,
					Interval:   interval,
				}
			}
			wg.Done()
		}(&wg, req)
	}
	go func() {
		wg.Wait()
		close(seriesChan)
		close(errorsChan)
	}()
	out := make([]Series, 0, len(reqs))
	var err error
	for series := range seriesChan {
		out = append(out, series)
	}
	for e := range errorsChan {
		err = e
		break
	}
	return out, err

}

func getTarget(store Store, req Req) (points []Point, interval uint32, err error) {
	defer doRecover(&err)

	readConsolidated := req.archive != 0   // do we need to read from a downsampled series?
	runtimeConsolidation := req.aggNum > 1 // do we need to compress any points at runtime?

	log.Debug("getTarget()         %s", req)
	log.Debug("type   interval   points")

	if runtimeConsolidation {
		log.Debug("runtimeConsolidation: true. agg factor: %d -> output interval: %d", req.aggNum, req.outInterval)
	} else {
		log.Debug("runtimeConsolidation: false. output interval: %d", req.outInterval)
	}

	if !readConsolidated && !runtimeConsolidation {
		return fix(
			getSeries(store, req.key, consolidation.None, 0, req.from, req.to),
			req.from,
			req.to,
			req.archInterval,
		), req.outInterval, nil
	} else if !readConsolidated && runtimeConsolidation {
		return consolidate(
			fix(
				getSeries(store, req.key, consolidation.None, 0, req.from, req.to),
				req.from,
				req.to,
				req.archInterval,
			),
			req.aggNum,
			req.consolidator), req.outInterval, nil
	} else if readConsolidated && !runtimeConsolidation {
		if req.consolidator == consolidation.Avg {
			return divide(
				fix(
					getSeries(store, req.key, consolidation.Sum, req.archInterval, req.from, req.to),
					req.from,
					req.to,
					req.archInterval,
				),
				fix(
					getSeries(store, req.key, consolidation.Cnt, req.archInterval, req.from, req.to),
					req.from,
					req.to,
					req.archInterval,
				),
			), req.outInterval, nil
		} else {
			return fix(
				getSeries(store, req.key, req.consolidator, req.archInterval, req.from, req.to),
				req.from,
				req.to,
				req.archInterval,
			), req.outInterval, nil
		}
	} else {
		// readConsolidated && runtimeConsolidation
		if req.consolidator == consolidation.Avg {
			return divide(
				consolidate(
					fix(
						getSeries(store, req.key, consolidation.Sum, req.archInterval, req.from, req.to),
						req.from,
						req.to,
						req.archInterval,
					),
					req.aggNum,
					consolidation.Sum),
				consolidate(
					fix(
						getSeries(store, req.key, consolidation.Cnt, req.archInterval, req.from, req.to),
						req.from,
						req.to,
						req.archInterval,
					),
					req.aggNum,
					consolidation.Sum),
			), req.outInterval, nil
		} else {
			return consolidate(
				fix(
					getSeries(store, req.key, req.consolidator, req.archInterval, req.from, req.to),
					req.from,
					req.to,
					req.archInterval,
				),
				req.aggNum, req.consolidator), req.outInterval, nil
		}
	}
}

func logLoad(typ, key string, from, to uint32) {
	log.Debug("load from %-6s %-20s %d - %d (%s - %s) span:%ds", typ, key, from, to, TS(from), TS(to), to-from-1)
}

func aggMetricKey(key, archive string, aggSpan uint32) string {
	return fmt.Sprintf("%s_%s_%d", key, archive, aggSpan)
}

// getSeries just gets the needed raw iters from mem and/or cassandra, based on from/to
// it can query for data within aggregated archives, by using fn min/max/sum/cnt and providing the matching agg span.
func getSeries(store Store, key string, consolidator consolidation.Consolidator, aggSpan, fromUnix, toUnix uint32) []Point {
	iters := make([]Iter, 0)
	memIters := make([]Iter, 0)
	oldest := toUnix
	if metric, ok := metrics.Get(key); ok {
		if consolidator != consolidation.None {
			logLoad("memory", aggMetricKey(key, consolidator.Archive(), aggSpan), fromUnix, toUnix)
			oldest, memIters = metric.GetAggregated(consolidator, aggSpan, fromUnix, toUnix)
		} else {
			logLoad("memory", key, fromUnix, toUnix)
			oldest, memIters = metric.Get(fromUnix, toUnix)
		}
	}
	if oldest > fromUnix {
		reqSpanBoth.Value(int64(toUnix - fromUnix))
		if consolidator != consolidation.None {
			key = aggMetricKey(key, consolidator.Archive(), aggSpan)
		}
		// if oldest < to -> search until oldest, we already have the rest from mem
		// if to < oldest -> no need to search until oldest, only search until to
		until := min(oldest, toUnix)
		logLoad("cassan", key, fromUnix, until)
		storeIters, err := store.Search(key, fromUnix, until)
		if err != nil {
			panic(err)
		}
		iters = append(iters, storeIters...)
	} else {
		reqSpanMem.Value(int64(toUnix - fromUnix))
	}
	pre := time.Now()
	iters = append(iters, memIters...)

	points := make([]Point, 0)
	for _, iter := range iters {
		total := 0
		good := 0
		for iter.Next() {
			total += 1
			ts, val := iter.Values()
			if ts >= fromUnix && ts < toUnix {
				good += 1
				points = append(points, Point{val, ts})
			}
		}
		log.Debug("getSeries: iter %s  values good/total %d/%d", iter.cmt, good, total)
	}
	itersToPointsDuration.Value(time.Now().Sub(pre))
	return points
}
<|endoftext|>


<commit_before>package libsysinfo

import (
	"os/exec"
	"strings"
)

const ()

var (
	cacheKeys = map[string]string{
		"HOSTNAME_FULL":      "fullhostname",
		"HOSTNAME":           "hostname",
		"DOMAIN_NAME":        "domainname",
		"LSB_FULL":           "lsbfull",
		"LSB_DIST_CODE_NAME": "lsbdistcodename",
	}

	globalCache = NewCachedValues(len(cacheKeys))
)

func Hostname() (string, error) {
	llv := &lazyLoadedValue{
		CacheKey:    cacheKeys["HOSTNAME"],
		Fetcher:     getFullHostname,
		Processor:   processHostname,
		CacheBucket: globalCache,
	}

	return llv.run()
}

func Domain() (string, error) {
	llv := &lazyLoadedValue{
		CacheKey:    cacheKeys["DOMAIN_NAME"],
		Fetcher:     getFullHostname,
		Processor:   processDomainName,
		CacheBucket: globalCache,
	}

	return llv.run()
}

func Fqdn() (string, error) {
	fqdn := func(fullHostname string) (string, error) {
		return fullHostname, nil
	}

	llv := &lazyLoadedValue{
		CacheKey:    cacheKeys["FQDN"],
		Fetcher:     getFullHostname,
		Processor:   fqdn,
		CacheBucket: globalCache,
	}

	return llv.run()
}

func LsbDistCodeName() (string, error) {
	return lsbDist("LSB_DIST_CODE_NAME", "Codename")
}

func lsbDist(k string, lsbItem string) (string, error) {
	proc := func(lsb string) (string, error) {
		return processLsbItem(lsb, lsbItem)
	}

	llv := &lazyLoadedValue{
		CacheKey:    cacheKeys[k],
		Fetcher:     getLsbRelease,
		Processor:   proc,
		CacheBucket: globalCache,
	}

	return llv.run()
}

func processDomainName(fullHostname string) (string, error) {
	pos := strings.Index(fullHostname, ".")
	if pos == -1 {
		return "", nil
	}

	return fullHostname[pos+1:], nil
}

func processHostname(fullHostname string) (string, error) {
	pos := strings.Index(fullHostname, ".")
	if pos == -1 {
		return fullHostname, nil
	}

	return fullHostname[:pos], nil
}

func processLsbItem(lsb string, item string) (string, error) {
	var out string
	var tmp string

	for _, line := range strings.Split(lsb, "\n") {
		if len(line) <= 0 {
			continue
		}

		tmp = line[0:len(item)]
		if tmp == item {
			out = strings.TrimSpace(strings.TrimLeft(line, item+":"))
			break
		}
	}

	return strings.ToLower(out), nil
}

func getFullHostname() (string, error) {
	cacheKey := cacheKeys["HOSTNAME_FULL"]

	hf, exists := globalCache.Exists(cacheKey)
	if exists {
		return hf, nil
	}

	out, err := exec.Command("hostname", "-f").Output()
	if err != nil {
		return string(out), err
	}

	hf = string(out)

	// removing \n
	pos := strings.Index(hf, "\n")
	if pos > -1 {
		hf = hf[:pos]
	}

	globalCache.Set(cacheKey, hf)

	return hf, nil
}

func getLsbRelease() (string, error) {
	cacheKey := cacheKeys["LSB_FULL"]

	lsb, exists := globalCache.Exists(cacheKey)
	if exists {
		return lsb, nil
	}

	out, err := exec.Command("lsb_release", "-a").Output()
	if err != nil {
		return string(out), err
	}

	lsb = string(out)

	globalCache.Set(cacheKey, lsb)

	return lsb, nil
}
<commit_msg>Added LsbDistDescription()<commit_after>package libsysinfo

import (
	"os/exec"
	"strings"
)

const ()

var (
	cacheKeys = map[string]string{
		"HOSTNAME_FULL":        "fullhostname",
		"HOSTNAME":             "hostname",
		"DOMAIN_NAME":          "domainname",
		"LSB_FULL":             "lsbfull",
		"LSB_DIST_CODE_NAME":   "lsbdistcodename",
		"LSB_DIST_DESCRIPTION": "lsbdistdescrption",
	}

	globalCache = NewCachedValues(len(cacheKeys))
)

func Hostname() (string, error) {
	llv := &lazyLoadedValue{
		CacheKey:    cacheKeys["HOSTNAME"],
		Fetcher:     getFullHostname,
		Processor:   processHostname,
		CacheBucket: globalCache,
	}

	return llv.run()
}

func Domain() (string, error) {
	llv := &lazyLoadedValue{
		CacheKey:    cacheKeys["DOMAIN_NAME"],
		Fetcher:     getFullHostname,
		Processor:   processDomainName,
		CacheBucket: globalCache,
	}

	return llv.run()
}

func Fqdn() (string, error) {
	fqdn := func(fullHostname string) (string, error) {
		return fullHostname, nil
	}

	llv := &lazyLoadedValue{
		CacheKey:    cacheKeys["FQDN"],
		Fetcher:     getFullHostname,
		Processor:   fqdn,
		CacheBucket: globalCache,
	}

	return llv.run()
}

func LsbDistCodeName() (string, error) {
	return lsbDist("LSB_DIST_CODE_NAME", "Codename")
}

func LsbDistDescription() (string, error) {
	return lsbDist("LSB_DIST_DESCRIPTION", "Description")
}

func lsbDist(k string, lsbItem string) (string, error) {
	proc := func(lsb string) (string, error) {
		return processLsbItem(lsb, lsbItem)
	}

	llv := &lazyLoadedValue{
		CacheKey:    cacheKeys[k],
		Fetcher:     getLsbRelease,
		Processor:   proc,
		CacheBucket: globalCache,
	}

	return llv.run()
}

func processDomainName(fullHostname string) (string, error) {
	pos := strings.Index(fullHostname, ".")
	if pos == -1 {
		return "", nil
	}

	return fullHostname[pos+1:], nil
}

func processHostname(fullHostname string) (string, error) {
	pos := strings.Index(fullHostname, ".")
	if pos == -1 {
		return fullHostname, nil
	}

	return fullHostname[:pos], nil
}

func processLsbItem(lsb string, item string) (string, error) {
	var out string
	var tmp string

	for _, line := range strings.Split(lsb, "\n") {
		if len(line) <= 0 {
			continue
		}

		tmp = line[0:len(item)]
		if tmp == item {
			out = strings.TrimSpace(strings.TrimLeft(line, item+":"))
			break
		}
	}

	return strings.ToLower(out), nil
}

func getFullHostname() (string, error) {
	cacheKey := cacheKeys["HOSTNAME_FULL"]

	hf, exists := globalCache.Exists(cacheKey)
	if exists {
		return hf, nil
	}

	out, err := exec.Command("hostname", "-f").Output()
	if err != nil {
		return string(out), err
	}

	hf = string(out)

	// removing \n
	pos := strings.Index(hf, "\n")
	if pos > -1 {
		hf = hf[:pos]
	}

	globalCache.Set(cacheKey, hf)

	return hf, nil
}

func getLsbRelease() (string, error) {
	cacheKey := cacheKeys["LSB_FULL"]

	lsb, exists := globalCache.Exists(cacheKey)
	if exists {
		return lsb, nil
	}

	out, err := exec.Command("lsb_release", "-a").Output()
	if err != nil {
		return string(out), err
	}

	lsb = string(out)

	globalCache.Set(cacheKey, lsb)

	return lsb, nil
}
<|endoftext|>


<commit_before>// Copyright 2016 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"net/http"

	"v.io/x/ref/services/allocator"
)

func handleHome(ss *serverState, rs *requestState) error {
	ctx := ss.ctx
	instances, err := serverInstances(ctx, rs.email)
	if err != nil {
		return fmt.Errorf("list error: %v", err)
	}
	type instanceArg struct {
		Instance allocator.Instance
		DestroyURL,
		ResetURL,
		DebugURL,
		DashboardURL,
		SuspendURL,
		ResumeURL string
	}
	tmplArgs := struct {
		AssetsPrefix,
		ServerName,
		Email,
		CreateURL,
		Message string
		Instances []instanceArg
	}{
		AssetsPrefix: ss.args.staticAssetsPrefix,
		ServerName:   ss.args.serverName,
		Email:        rs.email,
		CreateURL:    makeURL(ctx, routeCreate, params{paramCSRF: rs.csrfToken}),
		Message:      rs.r.FormValue(paramMessage),
	}
	for _, instance := range instances {
		tmplArgs.Instances = append(tmplArgs.Instances, instanceArg{
			Instance:     instance,
			DestroyURL:   makeURL(ctx, routeDestroy, params{paramInstance: instance.Handle, paramCSRF: rs.csrfToken}),
			ResetURL:     makeURL(ctx, routeReset, params{paramInstance: instance.Handle, paramCSRF: rs.csrfToken}),
			SuspendURL:   makeURL(ctx, routeSuspend, params{paramInstance: instance.Handle, paramCSRF: rs.csrfToken}),
			ResumeURL:    makeURL(ctx, routeResume, params{paramInstance: instance.Handle, paramCSRF: rs.csrfToken}),
			DashboardURL: makeURL(ctx, routeDashboard, params{paramInstance: instance.Handle}),
			DebugURL:     makeURL(ctx, routeDebug+"/", params{paramMountName: instance.MountName}),
		})
	}
	if err := ss.args.assets.executeTemplate(rs.w, homeTmpl, tmplArgs); err != nil {
		return fmt.Errorf("failed to render home template: %v", err)
	}
	return nil
}

func handleCreate(ss *serverState, rs *requestState) error {
	ctx := ss.ctx
	instance, err := create(ctx, rs.email, ss.args.baseBlessings, ss.args.baseBlessingNames)
	if err != nil {
		return fmt.Errorf("create failed: %v", err)
	}
	redirectTo := makeURL(ctx, routeHome, params{paramMessage: "created " + instance})
	http.Redirect(rs.w, rs.r, redirectTo, http.StatusFound)
	return nil
}

func handleDestroy(ss *serverState, rs *requestState) error {
	ctx := ss.ctx
	instance := rs.r.FormValue(paramInstance)
	if instance == "" {
		return fmt.Errorf("parameter %q required for instance name", paramInstance)
	}
	if err := destroy(ctx, rs.email, instance); err != nil {
		return fmt.Errorf("destroy failed: %v", err)
	}
	redirectTo := makeURL(ctx, routeHome, params{paramMessage: "destroyed " + instance})
	http.Redirect(rs.w, rs.r, redirectTo, http.StatusFound)
	return nil
}

func handleSuspend(ss *serverState, rs *requestState) error {
	ctx := ss.ctx
	instance := rs.r.FormValue(paramInstance)
	if instance == "" {
		return fmt.Errorf("parameter %q required for instance name", paramInstance)
	}
	if err := suspend(ctx, rs.email, instance); err != nil {
		return fmt.Errorf("suspend failed: %v", err)
	}
	redirectTo := makeURL(ctx, routeHome, params{paramMessage: "suspended " + instance})
	http.Redirect(rs.w, rs.r, redirectTo, http.StatusFound)
	return nil
}

func handleResume(ss *serverState, rs *requestState) error {
	ctx := ss.ctx
	instance := rs.r.FormValue(paramInstance)
	if instance == "" {
		return fmt.Errorf("parameter %q required for instance name", paramInstance)
	}
	if err := resume(ctx, rs.email, instance); err != nil {
		return fmt.Errorf("resume failed: %v", err)
	}
	redirectTo := makeURL(ctx, routeHome, params{paramMessage: "resumed " + instance})
	http.Redirect(rs.w, rs.r, redirectTo, http.StatusFound)
	return nil
}

func handleReset(ss *serverState, rs *requestState) error {
	ctx := ss.ctx
	instance := rs.r.FormValue(paramInstance)
	if instance == "" {
		return fmt.Errorf("parameter %q required for instance name", paramInstance)
	}
	if err := resetDisk(ctx, rs.email, instance); err != nil {
		return fmt.Errorf("reset failed: %v", err)
	}
	redirectTo := makeURL(ctx, routeHome, params{paramMessage: "resetted " + instance})
	http.Redirect(rs.w, rs.r, redirectTo, http.StatusFound)
	return nil
}

func handleDebug(ss *serverState, rs *requestState, debugBrowserServeMux *http.ServeMux) error {
	ctx := ss.ctx
	mountName := rs.r.FormValue(paramMountName)
	if mountName == "" {
		return fmt.Errorf("parameter %q required for instance mount name", paramMountName)
	}
	if err := checkOwnerOfMountName(ctx, rs.email, mountName); err != nil {
		return err
	}
	http.StripPrefix(routeDebug, debugBrowserServeMux).ServeHTTP(rs.w, rs.r)
	return nil
}
<commit_msg>allocatord: sort instances by creation time in UI<commit_after>// Copyright 2016 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"net/http"
	"sort"

	"v.io/x/ref/services/allocator"
)

type byCreationTime []allocator.Instance

func (c byCreationTime) Len() int           { return len(c) }
func (c byCreationTime) Swap(i, j int)      { c[i], c[j] = c[j], c[i] }
func (c byCreationTime) Less(i, j int) bool { return c[i].CreationTime.After(c[j].CreationTime) }

func handleHome(ss *serverState, rs *requestState) error {
	ctx := ss.ctx
	instances, err := serverInstances(ctx, rs.email)
	if err != nil {
		return fmt.Errorf("list error: %v", err)
	}
	sort.Sort(byCreationTime(instances))
	type instanceArg struct {
		Instance allocator.Instance
		DestroyURL,
		ResetURL,
		DebugURL,
		DashboardURL,
		SuspendURL,
		ResumeURL string
	}
	tmplArgs := struct {
		AssetsPrefix,
		ServerName,
		Email,
		CreateURL,
		Message string
		Instances []instanceArg
	}{
		AssetsPrefix: ss.args.staticAssetsPrefix,
		ServerName:   ss.args.serverName,
		Email:        rs.email,
		CreateURL:    makeURL(ctx, routeCreate, params{paramCSRF: rs.csrfToken}),
		Message:      rs.r.FormValue(paramMessage),
	}
	for _, instance := range instances {
		tmplArgs.Instances = append(tmplArgs.Instances, instanceArg{
			Instance:     instance,
			DestroyURL:   makeURL(ctx, routeDestroy, params{paramInstance: instance.Handle, paramCSRF: rs.csrfToken}),
			ResetURL:     makeURL(ctx, routeReset, params{paramInstance: instance.Handle, paramCSRF: rs.csrfToken}),
			SuspendURL:   makeURL(ctx, routeSuspend, params{paramInstance: instance.Handle, paramCSRF: rs.csrfToken}),
			ResumeURL:    makeURL(ctx, routeResume, params{paramInstance: instance.Handle, paramCSRF: rs.csrfToken}),
			DashboardURL: makeURL(ctx, routeDashboard, params{paramInstance: instance.Handle}),
			DebugURL:     makeURL(ctx, routeDebug+"/", params{paramMountName: instance.MountName}),
		})
	}
	if err := ss.args.assets.executeTemplate(rs.w, homeTmpl, tmplArgs); err != nil {
		return fmt.Errorf("failed to render home template: %v", err)
	}
	return nil
}

func handleCreate(ss *serverState, rs *requestState) error {
	ctx := ss.ctx
	instance, err := create(ctx, rs.email, ss.args.baseBlessings, ss.args.baseBlessingNames)
	if err != nil {
		return fmt.Errorf("create failed: %v", err)
	}
	redirectTo := makeURL(ctx, routeHome, params{paramMessage: "created " + instance})
	http.Redirect(rs.w, rs.r, redirectTo, http.StatusFound)
	return nil
}

func handleDestroy(ss *serverState, rs *requestState) error {
	ctx := ss.ctx
	instance := rs.r.FormValue(paramInstance)
	if instance == "" {
		return fmt.Errorf("parameter %q required for instance name", paramInstance)
	}
	if err := destroy(ctx, rs.email, instance); err != nil {
		return fmt.Errorf("destroy failed: %v", err)
	}
	redirectTo := makeURL(ctx, routeHome, params{paramMessage: "destroyed " + instance})
	http.Redirect(rs.w, rs.r, redirectTo, http.StatusFound)
	return nil
}

func handleSuspend(ss *serverState, rs *requestState) error {
	ctx := ss.ctx
	instance := rs.r.FormValue(paramInstance)
	if instance == "" {
		return fmt.Errorf("parameter %q required for instance name", paramInstance)
	}
	if err := suspend(ctx, rs.email, instance); err != nil {
		return fmt.Errorf("suspend failed: %v", err)
	}
	redirectTo := makeURL(ctx, routeHome, params{paramMessage: "suspended " + instance})
	http.Redirect(rs.w, rs.r, redirectTo, http.StatusFound)
	return nil
}

func handleResume(ss *serverState, rs *requestState) error {
	ctx := ss.ctx
	instance := rs.r.FormValue(paramInstance)
	if instance == "" {
		return fmt.Errorf("parameter %q required for instance name", paramInstance)
	}
	if err := resume(ctx, rs.email, instance); err != nil {
		return fmt.Errorf("resume failed: %v", err)
	}
	redirectTo := makeURL(ctx, routeHome, params{paramMessage: "resumed " + instance})
	http.Redirect(rs.w, rs.r, redirectTo, http.StatusFound)
	return nil
}

func handleReset(ss *serverState, rs *requestState) error {
	ctx := ss.ctx
	instance := rs.r.FormValue(paramInstance)
	if instance == "" {
		return fmt.Errorf("parameter %q required for instance name", paramInstance)
	}
	if err := resetDisk(ctx, rs.email, instance); err != nil {
		return fmt.Errorf("reset failed: %v", err)
	}
	redirectTo := makeURL(ctx, routeHome, params{paramMessage: "resetted " + instance})
	http.Redirect(rs.w, rs.r, redirectTo, http.StatusFound)
	return nil
}

func handleDebug(ss *serverState, rs *requestState, debugBrowserServeMux *http.ServeMux) error {
	ctx := ss.ctx
	mountName := rs.r.FormValue(paramMountName)
	if mountName == "" {
		return fmt.Errorf("parameter %q required for instance mount name", paramMountName)
	}
	if err := checkOwnerOfMountName(ctx, rs.email, mountName); err != nil {
		return err
	}
	http.StripPrefix(routeDebug, debugBrowserServeMux).ServeHTTP(rs.w, rs.r)
	return nil
}
<|endoftext|>