<commit_before>package command

import (
	"bytes"
	"crypto/rand"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"html/template"
	"io/ioutil"
	"os"
	"strings"
	"time"

	"koding/db/models"
	"koding/db/mongodb/modelhelper"

	"github.com/fatih/structs"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

// MachineSpec describes data needed to create a machine, thus a "spec".
type MachineSpec struct {
	Environment string         `json:"environment,omitempty"`
	User        models.User    `json:"user,omitempty"`
	Machine     models.Machine `json:"machine,omitempty"`
}

// HasMachine returns true when spec describes aleady existing machine.
func (spec *MachineSpec) HasMachine() bool {
	return spec.Machine.ObjectId.Valid()
}

// HasUser returns true when spec describes already existing user.
func (spec *MachineSpec) HasUser() bool {
	if spec.User.ObjectId.Valid() {
		return true
	}
	return len(spec.Machine.Users) != 0 && spec.Machine.Users[0].Id.Valid()
}

// HasGroup returns true when spec describes already existing group.
func (spec *MachineSpec) HasGroup() bool {
	return len(spec.Machine.Groups) != 0 && spec.Machine.Groups[0].Id.Valid()
}

// Username returns the name of the user the requests machine creation.
func (spec *MachineSpec) Username() string {
	if spec.User.Name != "" {
		return spec.User.Name
	}
	if len(spec.Machine.Users) == 0 {
		return ""
	}
	return spec.Machine.Users[0].Username
}

// Domain returns the domain of the machine.
func (spec *MachineSpec) Domain() string {
	return fmt.Sprintf("%s.%s.%s", spec.Machine.Uid, spec.Machine.Credential, dnsZones[spec.env()])
}

func (spec *MachineSpec) finalizeUID() string {
	return spec.Machine.Uid[:4] + shortUID()
}

func (spec *MachineSpec) env() string {
	if spec.Environment != "" {
		return spec.Environment
	}
	return "dev"
}

// MachineSpecVars represents variables accessible from within the spec template.
type MachineSpecVars struct {
	Env         string `json:"env,omitempty"`
	UserID      string `json:"userId,omitempty"`
	Username    string `json:"username,omitempty"`
	Email       string `json:"email,omitempty"`
	Salt        string `json:"salt,omitempty"`
	Password    string `json:"password,omitempty"`
	MachineID   string `json:"machineId,omitempty"`
	MachineName string `json:"machineName,omitempty"`
	TemplateID  string `json:"templateId,omitempty"`
	GroupID     string `json:"groupId,omitempty"`
	Datacenter  string `json:"datacenter,omitempty"`
	Region      string `json:"region,omitempty"`
}

var defaultVars = &MachineSpecVars{
	Env:         "dev",
	Username:    "kloudctl",
	Email:       "rafal+kloudctl@koding.com",
	MachineName: "kloudctl",
	Datacenter:  "sjc01",
	Region:      "us-east-1",
}

// ParseMachineSpec parses the given spec file and templates the variables
// with the given vars.
func ParseMachineSpec(file string, vars *MachineSpecVars) (*MachineSpec, error) {
	var p []byte
	var err error
	if file == "-" {
		p, err = ioutil.ReadAll(os.Stdin)
	} else {
		p, err = ioutil.ReadFile(file)
	}
	if err != nil {
		return nil, err
	}
	if vars == nil {
		vars = defaultVars
	}
	tmpl, err := template.New("spec").Funcs(vars.Funcs()).Parse(string(p))
	if err != nil {
		return nil, err
	}
	var buf bytes.Buffer
	if err := tmpl.Execute(&buf, nil); err != nil {
		return nil, err
	}
	var spec MachineSpec
	if err := json.Unmarshal(buf.Bytes(), &spec); err != nil {
		return nil, err
	}
	return &spec, nil
}

// Var a value of the given variable. If the variable is not set, it is
// going to read VAR_<NAME> env.
func (vars *MachineSpecVars) Var(name string) string {
	if s := os.Getenv("VAR_" + strings.ToUpper(name)); s != "" {
		return s
	}
	field, ok := structs.New(vars).FieldOk(name)
	if ok {
		if s, ok := field.Value().(string); ok && s != "" {
			return s
		}
	}
	return ""
}

// Funcs returns text/template funcs.
func (vars *MachineSpecVars) Funcs() map[string]interface{} {
	return map[string]interface{}{
		"var": vars.Var,
	}
}

// BuildUserAndGroup ensures the user and group of the spec are
// inserted into db.
func (spec *MachineSpec) BuildUserAndGroup() error {
	// If MachineID is not nil, ensure it exists and reuse it if it does.
	if spec.HasMachine() {
		return modelhelper.Mongo.One("jMachines", spec.Machine.ObjectId.Hex(), &spec.Machine)
	}
	// If no existing group is provided, create or use 'hackathon' one,
	// which will make VMs invisible to users until they're assigned
	// to proper group before the hackathon.
	if !spec.HasGroup() {
		group, err := getOrCreateHackathonGroup()
		if err != nil {
			return err
		}
		if len(spec.Machine.Groups) == 0 {
			spec.Machine.Groups = make([]models.MachineGroup, 1)
		}
		spec.Machine.Groups[0].Id = group.Id
	}
	// If no existing user is provided, create one.
	if !spec.HasUser() {
		query := func(c *mgo.Collection) error {
			// Try to lookup user by username first.
			var user models.User
			err := c.Find(bson.M{"username": spec.Username()}).One(&user)
			if err == nil {
				spec.User.ObjectId = user.ObjectId
				spec.User.Name = spec.Username()
				return nil
			}
			// If the lookup fails, create new one.
			spec.User.ObjectId = bson.NewObjectId()
			if spec.User.RegisteredAt.IsZero() {
				spec.User.RegisteredAt = time.Now()
			}
			if spec.User.LastLoginDate.IsZero() {
				spec.User.LastLoginDate = spec.User.RegisteredAt
			}
			return c.Insert(&spec.User)
		}
		err := modelhelper.Mongo.Run("jUsers", query)
		if err != nil {
			return err
		}
		// For newly created user increment the member count.
		query = func(c *mgo.Collection) error {
			var group models.Group
			id := spec.Machine.Groups[0].Id
			err := c.FindId(id).One(&group)
			if err != nil {
				return err
			}
			var count int
			members, ok := group.Counts["members"]
			if ok {
				count, ok = members.(int)
				if !ok {
					// If the member count is unavaible to skip updating
					// and return.
					return nil
				}
			}
			group.Counts["members"] = count + 1
			return c.UpdateId(id, &group)
		}
		err = modelhelper.Mongo.Run("jGroups", query)
		if err != nil {
			return err
		}
	}
	// Ensure the user is assigned to the machine.
	if len(spec.Machine.Users) == 0 {
		spec.Machine.Users = make([]models.MachineUser, 1)
	}
	if spec.Machine.Users[0].Id == "" {
		spec.Machine.Users[0].Id = spec.User.ObjectId
	}
	if spec.Machine.Users[0].Username == "" {
		spec.Machine.Users[0].Username = spec.User.Name
	}
	// Lookup username for existing user.
	if spec.Machine.Users[0].Username == "" {
		var user models.User
		query := func(c *mgo.Collection) error {
			return c.FindId(spec.Machine.Users[0].Id).One(&user)
		}
		err := modelhelper.Mongo.Run("jUsers", query)
		if err != nil {
			return err
		}
		spec.Machine.Users[0].Username = user.Name
	}
	// Lookup group and init Uid.
	var group models.Group
	query := func(c *mgo.Collection) error {
		return c.FindId(spec.Machine.Groups[0].Id).One(&group)
	}
	if err := modelhelper.Mongo.Run("jGroups", query); err != nil {
		return err
	}
	spec.Machine.Uid = fmt.Sprintf("u%c%c%c",
		spec.Machine.Users[0].Username[0],
		group.Slug[0],
		spec.Machine.Provider[0],
	)
	return nil
}

// BuildMachine inserts the machine to DB and requests kloud to build it.
func (spec *MachineSpec) BuildMachine() error {
	// Insert the machine to the db.
	query := func(c *mgo.Collection) error {
		spec.Machine.ObjectId = bson.NewObjectId()
		spec.Machine.CreatedAt = time.Now()
		spec.Machine.Status.ModifiedAt = time.Now()
		spec.Machine.Credential = spec.Machine.Users[0].Username
		spec.Machine.Uid = spec.finalizeUID()
		spec.Machine.Domain = spec.Domain()
		return c.Insert(&spec.Machine)
	}
	return modelhelper.Mongo.Run("jMachines", query)
}

// Copy gives a copy of the spec value.
func (spec *MachineSpec) Copy() *MachineSpec {
	var specCopy MachineSpec
	p, err := json.Marshal(spec)
	if err != nil {
		panic("internal error copying a MachineSpec: " + err.Error())
	}
	err = json.Unmarshal(p, &specCopy)
	if err != nil {
		panic("internal error copying a MachineSpec: " + err.Error())
	}
	return &specCopy
}

var dnsZones = map[string]string{
	"dev":        "dev.koding.io",
	"sandbox":    "sandbox.koding.com",
	"production": "koding.com",
}

func getOrCreateHackathonGroup() (*models.Group, error) {
	var group models.Group
	query := func(c *mgo.Collection) error {
		err := c.Find(bson.M{"slug": "hackathon"}).One(&group)
		if err == mgo.ErrNotFound {
			group = models.Group{
				Id:         bson.NewObjectId(),
				Body:       "Preallocated VM pool for Hackathon",
				Title:      "Hackathon",
				Slug:       "hackathon",
				Privacy:    "private",
				Visibility: "invisible",
				Counts: map[string]interface{}{
					"members": 0,
				},
			}
			err = c.Insert(&group)
		}
		return err
	}
	if err := modelhelper.Mongo.Run("jGroups", query); err != nil {
		return nil, err
	}
	return &group, nil
}

func shortUID() string {
	p := make([]byte, 4)
	_, err := rand.Read(p)
	if err != nil {
		panic("internal error running PRNG: " + err.Error())
	}
	return hex.EncodeToString(p)
}
<commit_msg>kloudctl: use modhelper funcs<commit_after>package command

import (
	"bytes"
	"crypto/rand"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"html/template"
	"io/ioutil"
	"os"
	"strings"
	"time"

	"koding/db/models"
	"koding/db/mongodb/modelhelper"

	"github.com/fatih/structs"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

// MachineSpec describes data needed to create a machine, thus a "spec".
type MachineSpec struct {
	Environment string         `json:"environment,omitempty"`
	User        models.User    `json:"user,omitempty"`
	Machine     models.Machine `json:"machine,omitempty"`
}

// HasMachine returns true when spec describes aleady existing machine.
func (spec *MachineSpec) HasMachine() bool {
	return spec.Machine.ObjectId.Valid()
}

// HasUser returns true when spec describes already existing user.
func (spec *MachineSpec) HasUser() bool {
	if spec.User.ObjectId.Valid() {
		return true
	}
	return len(spec.Machine.Users) != 0 && spec.Machine.Users[0].Id.Valid()
}

// HasGroup returns true when spec describes already existing group.
func (spec *MachineSpec) HasGroup() bool {
	return len(spec.Machine.Groups) != 0 && spec.Machine.Groups[0].Id.Valid()
}

// Username returns the name of the user the requests machine creation.
func (spec *MachineSpec) Username() string {
	if spec.User.Name != "" {
		return spec.User.Name
	}
	if len(spec.Machine.Users) == 0 {
		return ""
	}
	return spec.Machine.Users[0].Username
}

// Domain returns the domain of the machine.
func (spec *MachineSpec) Domain() string {
	return fmt.Sprintf("%s.%s.%s", spec.Machine.Uid, spec.Machine.Credential, dnsZones[spec.env()])
}

func (spec *MachineSpec) finalizeUID() string {
	return spec.Machine.Uid[:4] + shortUID()
}

func (spec *MachineSpec) env() string {
	if spec.Environment != "" {
		return spec.Environment
	}
	return "dev"
}

// MachineSpecVars represents variables accessible from within the spec template.
type MachineSpecVars struct {
	Env         string `json:"env,omitempty"`
	UserID      string `json:"userId,omitempty"`
	Username    string `json:"username,omitempty"`
	Email       string `json:"email,omitempty"`
	Salt        string `json:"salt,omitempty"`
	Password    string `json:"password,omitempty"`
	MachineID   string `json:"machineId,omitempty"`
	MachineName string `json:"machineName,omitempty"`
	TemplateID  string `json:"templateId,omitempty"`
	GroupID     string `json:"groupId,omitempty"`
	Datacenter  string `json:"datacenter,omitempty"`
	Region      string `json:"region,omitempty"`
}

var defaultVars = &MachineSpecVars{
	Env:         "dev",
	Username:    "kloudctl",
	Email:       "rafal+kloudctl@koding.com",
	MachineName: "kloudctl",
	Datacenter:  "sjc01",
	Region:      "us-east-1",
}

// ParseMachineSpec parses the given spec file and templates the variables
// with the given vars.
func ParseMachineSpec(file string, vars *MachineSpecVars) (*MachineSpec, error) {
	var p []byte
	var err error
	if file == "-" {
		p, err = ioutil.ReadAll(os.Stdin)
	} else {
		p, err = ioutil.ReadFile(file)
	}
	if err != nil {
		return nil, err
	}
	if vars == nil {
		vars = defaultVars
	}
	tmpl, err := template.New("spec").Funcs(vars.Funcs()).Parse(string(p))
	if err != nil {
		return nil, err
	}
	var buf bytes.Buffer
	if err := tmpl.Execute(&buf, nil); err != nil {
		return nil, err
	}
	var spec MachineSpec
	if err := json.Unmarshal(buf.Bytes(), &spec); err != nil {
		return nil, err
	}
	return &spec, nil
}

// Var a value of the given variable. If the variable is not set, it is
// going to read VAR_<NAME> env.
func (vars *MachineSpecVars) Var(name string) string {
	if s := os.Getenv("VAR_" + strings.ToUpper(name)); s != "" {
		return s
	}
	field, ok := structs.New(vars).FieldOk(name)
	if ok {
		if s, ok := field.Value().(string); ok && s != "" {
			return s
		}
	}
	return ""
}

// Funcs returns text/template funcs.
func (vars *MachineSpecVars) Funcs() map[string]interface{} {
	return map[string]interface{}{
		"var": vars.Var,
	}
}

// BuildUserAndGroup ensures the user and group of the spec are
// inserted into db.
func (spec *MachineSpec) BuildUserAndGroup() error {
	// If MachineID is not nil, ensure it exists and reuse it if it does.
	if spec.HasMachine() {
		m, err := modelhelper.GetMachine(spec.Machine.ObjectId.Hex())
		if err != nil {
			return err
		}
		spec.Machine = *m
		return nil
	}
	// If no existing group is provided, create or use 'hackathon' one,
	// which will make VMs invisible to users until they're assigned
	// to proper group before the hackathon.
	if !spec.HasGroup() {
		group, err := getOrCreateHackathonGroup()
		if err != nil {
			return err
		}
		if len(spec.Machine.Groups) == 0 {
			spec.Machine.Groups = make([]models.MachineGroup, 1)
		}
		spec.Machine.Groups[0].Id = group.Id
	}
	// If no existing user is provided, create one.
	if !spec.HasUser() {
		query := func(c *mgo.Collection) error {
			// Try to lookup user by username first.
			var user models.User
			err := c.Find(bson.M{"username": spec.Username()}).One(&user)
			if err == nil {
				spec.User.ObjectId = user.ObjectId
				spec.User.Name = spec.Username()
				return nil
			}
			// If the lookup fails, create new one.
			spec.User.ObjectId = bson.NewObjectId()
			if spec.User.RegisteredAt.IsZero() {
				spec.User.RegisteredAt = time.Now()
			}
			if spec.User.LastLoginDate.IsZero() {
				spec.User.LastLoginDate = spec.User.RegisteredAt
			}
			return c.Insert(&spec.User)
		}
		err := modelhelper.Mongo.Run("jUsers", query)
		if err != nil {
			return err
		}
		// For newly created user increment the member count.
		query = func(c *mgo.Collection) error {
			var group models.Group
			id := spec.Machine.Groups[0].Id
			err := c.FindId(id).One(&group)
			if err != nil {
				return err
			}
			var count int
			members, ok := group.Counts["members"]
			if ok {
				count, ok = members.(int)
				if !ok {
					// If the member count is unavaible to skip updating
					// and return.
					return nil
				}
			}
			group.Counts["members"] = count + 1
			return c.UpdateId(id, &group)
		}
		err = modelhelper.Mongo.Run("jGroups", query)
		if err != nil {
			return err
		}
	}
	// Ensure the user is assigned to the machine.
	if len(spec.Machine.Users) == 0 {
		spec.Machine.Users = make([]models.MachineUser, 1)
	}
	if spec.Machine.Users[0].Id == "" {
		spec.Machine.Users[0].Id = spec.User.ObjectId
	}
	if spec.Machine.Users[0].Username == "" {
		spec.Machine.Users[0].Username = spec.User.Name
	}
	// Lookup username for existing user.
	if spec.Machine.Users[0].Username == "" {
		user, err := modelhelper.GetUserById(spec.Machine.Users[0].Id.Hex())
		if err != nil {
			return err
		}
		spec.Machine.Users[0].Username = user.Name
	}
	// Lookup group and init Uid.
	group, err := modelhelper.GetGroupById(spec.Machine.Groups[0].Id.Hex())
	if err != nil {
		return err
	}
	spec.Machine.Uid = fmt.Sprintf("u%c%c%c",
		spec.Machine.Users[0].Username[0],
		group.Slug[0],
		spec.Machine.Provider[0],
	)
	return nil
}

// BuildMachine inserts the machine to DB and requests kloud to build it.
func (spec *MachineSpec) BuildMachine() error {
	// Insert the machine to the db.
	query := func(c *mgo.Collection) error {
		spec.Machine.ObjectId = bson.NewObjectId()
		spec.Machine.CreatedAt = time.Now()
		spec.Machine.Status.ModifiedAt = time.Now()
		spec.Machine.Credential = spec.Machine.Users[0].Username
		spec.Machine.Uid = spec.finalizeUID()
		spec.Machine.Domain = spec.Domain()
		return c.Insert(&spec.Machine)
	}
	return modelhelper.Mongo.Run("jMachines", query)
}

// Copy gives a copy of the spec value.
func (spec *MachineSpec) Copy() *MachineSpec {
	var specCopy MachineSpec
	p, err := json.Marshal(spec)
	if err != nil {
		panic("internal error copying a MachineSpec: " + err.Error())
	}
	err = json.Unmarshal(p, &specCopy)
	if err != nil {
		panic("internal error copying a MachineSpec: " + err.Error())
	}
	return &specCopy
}

var dnsZones = map[string]string{
	"dev":        "dev.koding.io",
	"sandbox":    "sandbox.koding.com",
	"production": "koding.com",
}

func getOrCreateHackathonGroup() (*models.Group, error) {
	var group models.Group
	query := func(c *mgo.Collection) error {
		err := c.Find(bson.M{"slug": "hackathon"}).One(&group)
		if err == mgo.ErrNotFound {
			group = models.Group{
				Id:         bson.NewObjectId(),
				Body:       "Preallocated VM pool for Hackathon",
				Title:      "Hackathon",
				Slug:       "hackathon",
				Privacy:    "private",
				Visibility: "invisible",
				Counts: map[string]interface{}{
					"members": 0,
				},
			}
			err = c.Insert(&group)
		}
		return err
	}
	if err := modelhelper.Mongo.Run("jGroups", query); err != nil {
		return nil, err
	}
	return &group, nil
}

func shortUID() string {
	p := make([]byte, 4)
	_, err := rand.Read(p)
	if err != nil {
		panic("internal error running PRNG: " + err.Error())
	}
	return hex.EncodeToString(p)
}
<|endoftext|>


<commit_before>package event_convert

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"regexp"
	"strconv"
	"math"
	"encoding/binary"

	"github.com/karimra/gnmic/formatters"
	"github.com/karimra/gnmic/types"
)

const (
	processorType = "event-convert"
	loggingPrefix = "[" + processorType + "] "
)

// Convert converts the value with key matching one of regexes, to the specified Type
type Convert struct {
	Values []string `mapstructure:"value-names,omitempty" json:"value-names,omitempty"`
	Type   string   `mapstructure:"type,omitempty" json:"type,omitempty"`
	Debug  bool     `mapstructure:"debug,omitempty" json:"debug,omitempty"`

	values []*regexp.Regexp
	logger *log.Logger
}

func init() {
	formatters.Register(processorType, func() formatters.EventProcessor {
		return &Convert{
			logger: log.New(ioutil.Discard, "", 0),
		}
	})
}

func (c *Convert) Init(cfg interface{}, opts ...formatters.Option) error {
	err := formatters.DecodeConfig(cfg, c)
	if err != nil {
		return err
	}
	for _, opt := range opts {
		opt(c)
	}
	c.values = make([]*regexp.Regexp, 0, len(c.Values))
	for _, reg := range c.Values {
		re, err := regexp.Compile(reg)
		if err != nil {
			return err
		}
		c.values = append(c.values, re)
	}
	if c.logger.Writer() != ioutil.Discard {
		b, err := json.Marshal(c)
		if err != nil {
			c.logger.Printf("initialized processor '%s': %+v", processorType, c)
			return nil
		}
		c.logger.Printf("initialized processor '%s': %s", processorType, string(b))
	}
	return nil
}

func (c *Convert) Apply(es ...*formatters.EventMsg) []*formatters.EventMsg {
	for _, e := range es {
		if e == nil {
			continue
		}
		for k, v := range e.Values {
			for _, re := range c.values {
				if re.MatchString(k) {
					c.logger.Printf("key '%s' matched regex '%s'", k, re.String())
					switch c.Type {
					case "int":
						iv, err := convertToInt(v)
						if err != nil {
							c.logger.Printf("convert error: %v", err)
							break
						}
						c.logger.Printf("key '%s', value %v converted to %s: %d", k, v, c.Type, iv)
						e.Values[k] = iv
					case "uint":
						iv, err := convertToUint(v)
						if err != nil {
							c.logger.Printf("convert error: %v", err)
							break
						}
						c.logger.Printf("key '%s', value %v converted to %s: %d", k, v, c.Type, iv)
						e.Values[k] = iv
					case "string":
						iv, err := convertToString(v)
						if err != nil {
							c.logger.Printf("convert error: %v", err)
							break
						}
						c.logger.Printf("key '%s', value %v converted to %s: %s", k, v, c.Type, iv)
						e.Values[k] = iv
					case "float":
						iv, err := convertToFloat(v)
						if err != nil {
							c.logger.Printf("convert error: %v", err)
							break
						}
						c.logger.Printf("key '%s', value %v converted to %s: %f", k, v, c.Type, iv)
						e.Values[k] = iv
					}
					break
				}
			}
		}
	}
	return es
}

func (c *Convert) WithLogger(l *log.Logger) {
	if c.Debug && l != nil {
		c.logger = log.New(l.Writer(), loggingPrefix, l.Flags())
	} else if c.Debug {
		c.logger = log.New(os.Stderr, loggingPrefix, log.LstdFlags|log.Lmicroseconds)
	}
}

func (c *Convert) WithTargets(tcs map[string]*types.TargetConfig) {}

func convertToInt(i interface{}) (int, error) {
	switch i := i.(type) {
	case string:
		iv, err := strconv.Atoi(i)
		if err != nil {
			return 0, err
		}
		return iv, nil
	case int:
		return i, nil
	case int8:
		return int(i), nil
	case int16:
		return int(i), nil
	case int32:
		return int(i), nil
	case int64:
		return int(i), nil
	case uint:
		return int(i), nil
	case uint8:
		return int(i), nil
	case uint16:
		return int(i), nil
	case uint32:
		return int(i), nil
	case uint64:
		return int(i), nil
	case float64:
		return int(i), nil
	case float32:
		return int(i), nil
	default:
		return 0, fmt.Errorf("cannot convert %v to int, type %T", i, i)
	}
}

func convertToUint(i interface{}) (uint, error) {
	switch i := i.(type) {
	case string:
		iv, err := strconv.Atoi(i)
		if err != nil {
			return 0, err
		}
		return uint(iv), nil
	case int:
		if i < 0 {
			return 0, nil
		}
		return uint(i), nil
	case int8:
		if i < 0 {
			return 0, nil
		}
		return uint(i), nil
	case int16:
		if i < 0 {
			return 0, nil
		}
		return uint(i), nil
	case int32:
		if i < 0 {
			return 0, nil
		}
		return uint(i), nil
	case int64:
		if i < 0 {
			return 0, nil
		}
		return uint(i), nil
	case uint:
		return i, nil
	case uint8:
		return uint(i), nil
	case uint16:
		return uint(i), nil
	case uint32:
		return uint(i), nil
	case uint64:
		return uint(i), nil
	case float32:
		if i < 0 {
			return 0, nil
		}
		return uint(i), nil
	case float64:
		if i < 0 {
			return 0, nil
		}
		return uint(i), nil
	default:
		return 0, fmt.Errorf("cannot convert %v to uint, type %T", i, i)
	}
}

func convertToFloat(i interface{}) (float64, error) {
	switch i := i.(type) {
	case []uint8:
	  ij := math.Float32frombits(binary.BigEndian.Uint32([]byte(i)))
	  return float64(ij), nil
	case string:
		iv, err := strconv.ParseFloat(i, 64)
		if err != nil {
			return 0, err
		}
		return iv, nil
	case int:
		return float64(i), nil
	case int8:
		return float64(i), nil
	case int16:
		return float64(i), nil
	case int32:
		return float64(i), nil
	case int64:
		return float64(i), nil
	case uint:
		return float64(i), nil
	case uint8:
		return float64(i), nil
	case uint16:
		return float64(i), nil
	case uint32:
		return float64(i), nil
	case uint64:
		return float64(i), nil
	case float64:
		return i, nil
	default:
		return 0, fmt.Errorf("cannot convert %v to float64, type %T", i, i)
	}
}

func convertToString(i interface{}) (string, error) {
	switch i := i.(type) {
	case string:
		return i, nil
	case int:
		return strconv.Itoa(i), nil
	case int8:
		return strconv.Itoa(int(i)), nil
	case int16:
		return strconv.Itoa(int(i)), nil
	case int32:
		return strconv.Itoa(int(i)), nil
	case int64:
		return strconv.Itoa(int(i)), nil
	case uint:
		return strconv.FormatUint(uint64(i), 10), nil
	case uint8:
		return strconv.FormatUint(uint64(i), 10), nil
	case uint16:
		return strconv.FormatUint(uint64(i), 10), nil
	case uint32:
		return strconv.FormatUint(uint64(i), 10), nil
	case uint64:
		return strconv.FormatUint(uint64(i), 10), nil
	case float64:
		return strconv.FormatFloat(i, 'f', -1, 64), nil
	case bool:
		return strconv.FormatBool(i), nil
	default:
		return "", fmt.Errorf("cannot convert %v to string, type %T", i, i)
	}
}
<commit_msg>Add check len for Binary Float on 32 bits and 64 bits<commit_after>package event_convert

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"regexp"
	"strconv"
	"math"
	"encoding/binary"

	"github.com/karimra/gnmic/formatters"
	"github.com/karimra/gnmic/types"
)

const (
	processorType = "event-convert"
	loggingPrefix = "[" + processorType + "] "
)

// Convert converts the value with key matching one of regexes, to the specified Type
type Convert struct {
	Values []string `mapstructure:"value-names,omitempty" json:"value-names,omitempty"`
	Type   string   `mapstructure:"type,omitempty" json:"type,omitempty"`
	Debug  bool     `mapstructure:"debug,omitempty" json:"debug,omitempty"`

	values []*regexp.Regexp
	logger *log.Logger
}

func init() {
	formatters.Register(processorType, func() formatters.EventProcessor {
		return &Convert{
			logger: log.New(ioutil.Discard, "", 0),
		}
	})
}

func (c *Convert) Init(cfg interface{}, opts ...formatters.Option) error {
	err := formatters.DecodeConfig(cfg, c)
	if err != nil {
		return err
	}
	for _, opt := range opts {
		opt(c)
	}
	c.values = make([]*regexp.Regexp, 0, len(c.Values))
	for _, reg := range c.Values {
		re, err := regexp.Compile(reg)
		if err != nil {
			return err
		}
		c.values = append(c.values, re)
	}
	if c.logger.Writer() != ioutil.Discard {
		b, err := json.Marshal(c)
		if err != nil {
			c.logger.Printf("initialized processor '%s': %+v", processorType, c)
			return nil
		}
		c.logger.Printf("initialized processor '%s': %s", processorType, string(b))
	}
	return nil
}

func (c *Convert) Apply(es ...*formatters.EventMsg) []*formatters.EventMsg {
	for _, e := range es {
		if e == nil {
			continue
		}
		for k, v := range e.Values {
			for _, re := range c.values {
				if re.MatchString(k) {
					c.logger.Printf("key '%s' matched regex '%s'", k, re.String())
					switch c.Type {
					case "int":
						iv, err := convertToInt(v)
						if err != nil {
							c.logger.Printf("convert error: %v", err)
							break
						}
						c.logger.Printf("key '%s', value %v converted to %s: %d", k, v, c.Type, iv)
						e.Values[k] = iv
					case "uint":
						iv, err := convertToUint(v)
						if err != nil {
							c.logger.Printf("convert error: %v", err)
							break
						}
						c.logger.Printf("key '%s', value %v converted to %s: %d", k, v, c.Type, iv)
						e.Values[k] = iv
					case "string":
						iv, err := convertToString(v)
						if err != nil {
							c.logger.Printf("convert error: %v", err)
							break
						}
						c.logger.Printf("key '%s', value %v converted to %s: %s", k, v, c.Type, iv)
						e.Values[k] = iv
					case "float":
						iv, err := convertToFloat(v)
						if err != nil {
							c.logger.Printf("convert error: %v", err)
							break
						}
						c.logger.Printf("key '%s', value %v converted to %s: %f", k, v, c.Type, iv)
						e.Values[k] = iv
					}
					break
				}
			}
		}
	}
	return es
}

func (c *Convert) WithLogger(l *log.Logger) {
	if c.Debug && l != nil {
		c.logger = log.New(l.Writer(), loggingPrefix, l.Flags())
	} else if c.Debug {
		c.logger = log.New(os.Stderr, loggingPrefix, log.LstdFlags|log.Lmicroseconds)
	}
}

func (c *Convert) WithTargets(tcs map[string]*types.TargetConfig) {}

func convertToInt(i interface{}) (int, error) {
	switch i := i.(type) {
	case string:
		iv, err := strconv.Atoi(i)
		if err != nil {
			return 0, err
		}
		return iv, nil
	case int:
		return i, nil
	case int8:
		return int(i), nil
	case int16:
		return int(i), nil
	case int32:
		return int(i), nil
	case int64:
		return int(i), nil
	case uint:
		return int(i), nil
	case uint8:
		return int(i), nil
	case uint16:
		return int(i), nil
	case uint32:
		return int(i), nil
	case uint64:
		return int(i), nil
	case float64:
		return int(i), nil
	case float32:
		return int(i), nil
	default:
		return 0, fmt.Errorf("cannot convert %v to int, type %T", i, i)
	}
}

func convertToUint(i interface{}) (uint, error) {
	switch i := i.(type) {
	case string:
		iv, err := strconv.Atoi(i)
		if err != nil {
			return 0, err
		}
		return uint(iv), nil
	case int:
		if i < 0 {
			return 0, nil
		}
		return uint(i), nil
	case int8:
		if i < 0 {
			return 0, nil
		}
		return uint(i), nil
	case int16:
		if i < 0 {
			return 0, nil
		}
		return uint(i), nil
	case int32:
		if i < 0 {
			return 0, nil
		}
		return uint(i), nil
	case int64:
		if i < 0 {
			return 0, nil
		}
		return uint(i), nil
	case uint:
		return i, nil
	case uint8:
		return uint(i), nil
	case uint16:
		return uint(i), nil
	case uint32:
		return uint(i), nil
	case uint64:
		return uint(i), nil
	case float32:
		if i < 0 {
			return 0, nil
		}
		return uint(i), nil
	case float64:
		if i < 0 {
			return 0, nil
		}
		return uint(i), nil
	default:
		return 0, fmt.Errorf("cannot convert %v to uint, type %T", i, i)
	}
}

func convertToFloat(i interface{}) (float64, error) {
	switch i := i.(type) {
	case []uint8:
		if len(i) == 4 {
	  	ij := math.Float32frombits(binary.BigEndian.Uint32([]byte(i)))
		} else if len(i) == 8 {
			ij := math.Float64frombits(binary.BigEndian.Uint64([]byte(i)))
		} else {
			return 0, nil
		}
	  return float64(ij), nil
	case string:
		iv, err := strconv.ParseFloat(i, 64)
		if err != nil {
			return 0, err
		}
		return iv, nil
	case int:
		return float64(i), nil
	case int8:
		return float64(i), nil
	case int16:
		return float64(i), nil
	case int32:
		return float64(i), nil
	case int64:
		return float64(i), nil
	case uint:
		return float64(i), nil
	case uint8:
		return float64(i), nil
	case uint16:
		return float64(i), nil
	case uint32:
		return float64(i), nil
	case uint64:
		return float64(i), nil
	case float64:
		return i, nil
	default:
		return 0, fmt.Errorf("cannot convert %v to float64, type %T", i, i)
	}
}

func convertToString(i interface{}) (string, error) {
	switch i := i.(type) {
	case string:
		return i, nil
	case int:
		return strconv.Itoa(i), nil
	case int8:
		return strconv.Itoa(int(i)), nil
	case int16:
		return strconv.Itoa(int(i)), nil
	case int32:
		return strconv.Itoa(int(i)), nil
	case int64:
		return strconv.Itoa(int(i)), nil
	case uint:
		return strconv.FormatUint(uint64(i), 10), nil
	case uint8:
		return strconv.FormatUint(uint64(i), 10), nil
	case uint16:
		return strconv.FormatUint(uint64(i), 10), nil
	case uint32:
		return strconv.FormatUint(uint64(i), 10), nil
	case uint64:
		return strconv.FormatUint(uint64(i), 10), nil
	case float64:
		return strconv.FormatFloat(i, 'f', -1, 64), nil
	case bool:
		return strconv.FormatBool(i), nil
	default:
		return "", fmt.Errorf("cannot convert %v to string, type %T", i, i)
	}
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go 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 strings

// Count UTF-8 sequences in s.
// Assumes s is well-formed.
export func utflen(s string) int {
	n := 0;
	for i := 0; i < len(s); i++ {
		if s[i]&0xC0 != 0x80 {
			n++
		}
	}
	return n
}

// Split string into array of UTF-8 sequences (still strings)
export func explode(s string) *[]string {
	a := new([]string, utflen(s));
	j := 0;
	for i := 0; i < len(a); i++ {
		ej := j;
		ej++;
		for ej < len(s) && (s[ej]&0xC0) == 0x80 {
			ej++
		}
		a[i] = s[j:ej];
		j = ej
	}
	return a
}

// Count non-overlapping instances of sep in s.
export func count(s, sep string) int {
	if sep == "" {
		return utflen(s)+1
	}
	c := sep[0];
	n := 0;
	for i := 0; i+len(sep) <= len(s); i++ {
		if s[i] == c && (len(sep) == 1 || s[i:i+len(sep)] == sep) {
			n++;
			i += len(sep)-1
		}
	}
	return n
}

// Return index of first instance of sep in s.
export func index(s, sep string) int {
	if sep == "" {
		return 0
	}
	c := sep[0];
	for i := 0; i+len(sep) <= len(s); i++ {
		if s[i] == c && (len(sep) == 1 || s[i:i+len(sep)] == sep) {
			return i
		}
	}
	return -1
}

// Split string into list of strings at separators
export func split(s, sep string) *[]string {
	if sep == "" {
		return explode(s)
	}
	c := sep[0];
	start := 0;
	n := count(s, sep)+1;
	a := new([]string, n);
	na := 0;
	for i := 0; i+len(sep) <= len(s); i++ {
		if s[i] == c && (len(sep) == 1 || s[i:i+len(sep)] == sep) {
			a[na] = s[start:i];
			na++;
			start = i+len(sep);
			i += len(sep)-1
		}
	}
	a[na] = s[start:len(s)];
	return a
}

// Join list of strings with separators between them.
export func join(a *[]string, sep string) string {
	if len(a) == 0 {
		return ""
	}
	if len(a) == 1 {
		return a[0]
	}
	n := len(sep) * (len(a)-1);
	for i := 0; i < len(a); i++ {
		n += len(a[i])
	}

	b := new([]byte, n);
	bp := 0;
	for i := 0; i < len(a); i++ {
		s := a[i];
		for j := 0; j < len(s); j++ {
			b[bp] = s[j];
			bp++
		}
		if i + 1 < len(a) {
			s = sep;
			for j := 0; j < len(s); j++ {
				b[bp] = s[j];
				bp++
			}
		}
	}
	return string(b)
}

// Convert decimal string to integer.
// TODO: Doesn't check for overflow.
export func atoi(s string) (i int, ok bool) {
	// empty string bad
	if len(s) == 0 {
		return 0, false
	}

	// pick off leading sign
	neg := false;
	if s[0] == '+' {
		s = s[1:len(s)]
	} else if s[0] == '-' {
		neg = true;
		s = s[1:len(s)]
	}

	// empty string bad
	if len(s) == 0 {
		return 0, false
	}

	// pick off zero
	if s == "0" {
		return 0, true
	}

	// otherwise, leading zero bad
	if s[0] == '0' {
		return 0, false
	}

	// parse number
	n := 0;
	for i := 0; i < len(s); i++ {
		if s[i] < '0' || s[i] > '9' {
			return 0, false
		}
		n = n*10 + int(s[i] - '0')
	}
	if neg {
		n = -n
	}
	return n, true
}

export func itoa(i int) string {
	if i == 0 {
		return "0"
	}

	neg := false;	// negative
	u := uint(i);
	if i < 0 {
		neg = true;
		u = -u;
	}

	// Assemble decimal in reverse order.
	var b [32]byte;
	bp := len(b);
	for ; u > 0; u /= 10 {
		bp--;
		b[bp] = byte(u%10) + '0'
	}
	if neg {	// add sign
		bp--;
		b[bp] = '-'
	}

	// BUG return string(b[bp:len(b)])
	return string((&b)[bp:len(b)])
}
<commit_msg>add atol and ltoa.  probably want unsigned at some point too.<commit_after>// Copyright 2009 The Go 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 strings

// Count UTF-8 sequences in s.
// Assumes s is well-formed.
export func utflen(s string) int {
	n := 0;
	for i := 0; i < len(s); i++ {
		if s[i]&0xC0 != 0x80 {
			n++
		}
	}
	return n
}

// Split string into array of UTF-8 sequences (still strings)
export func explode(s string) *[]string {
	a := new([]string, utflen(s));
	j := 0;
	for i := 0; i < len(a); i++ {
		ej := j;
		ej++;
		for ej < len(s) && (s[ej]&0xC0) == 0x80 {
			ej++
		}
		a[i] = s[j:ej];
		j = ej
	}
	return a
}

// Count non-overlapping instances of sep in s.
export func count(s, sep string) int {
	if sep == "" {
		return utflen(s)+1
	}
	c := sep[0];
	n := 0;
	for i := 0; i+len(sep) <= len(s); i++ {
		if s[i] == c && (len(sep) == 1 || s[i:i+len(sep)] == sep) {
			n++;
			i += len(sep)-1
		}
	}
	return n
}

// Return index of first instance of sep in s.
export func index(s, sep string) int {
	if sep == "" {
		return 0
	}
	c := sep[0];
	for i := 0; i+len(sep) <= len(s); i++ {
		if s[i] == c && (len(sep) == 1 || s[i:i+len(sep)] == sep) {
			return i
		}
	}
	return -1
}

// Split string into list of strings at separators
export func split(s, sep string) *[]string {
	if sep == "" {
		return explode(s)
	}
	c := sep[0];
	start := 0;
	n := count(s, sep)+1;
	a := new([]string, n);
	na := 0;
	for i := 0; i+len(sep) <= len(s); i++ {
		if s[i] == c && (len(sep) == 1 || s[i:i+len(sep)] == sep) {
			a[na] = s[start:i];
			na++;
			start = i+len(sep);
			i += len(sep)-1
		}
	}
	a[na] = s[start:len(s)];
	return a
}

// Join list of strings with separators between them.
export func join(a *[]string, sep string) string {
	if len(a) == 0 {
		return ""
	}
	if len(a) == 1 {
		return a[0]
	}
	n := len(sep) * (len(a)-1);
	for i := 0; i < len(a); i++ {
		n += len(a[i])
	}

	b := new([]byte, n);
	bp := 0;
	for i := 0; i < len(a); i++ {
		s := a[i];
		for j := 0; j < len(s); j++ {
			b[bp] = s[j];
			bp++
		}
		if i + 1 < len(a) {
			s = sep;
			for j := 0; j < len(s); j++ {
				b[bp] = s[j];
				bp++
			}
		}
	}
	return string(b)
}

// Convert decimal string to integer.
// TODO: Doesn't check for overflow.
export func atol(s string) (i int64, ok bool) {
	// empty string bad
	if len(s) == 0 {
		return 0, false
	}

	// pick off leading sign
	neg := false;
	if s[0] == '+' {
		s = s[1:len(s)]
	} else if s[0] == '-' {
		neg = true;
		s = s[1:len(s)]
	}

	// empty string bad
	if len(s) == 0 {
		return 0, false
	}

	// pick off zero
	if s == "0" {
		return 0, true
	}

	// otherwise, leading zero bad
	if s[0] == '0' {
		return 0, false
	}

	// parse number
	n := int64(0);
	for i := 0; i < len(s); i++ {
		if s[i] < '0' || s[i] > '9' {
			return 0, false
		}
		n = n*10 + int64(s[i] - '0')
	}
	if neg {
		n = -n
	}
	return n, true
}

export func atoi(s string) (i int, ok bool) {
	ii, okok := atoi(s);
	i = int32(ii);
	return i, okok
}

export func itol(i int64) string {
	if i == 0 {
		return "0"
	}

	neg := false;	// negative
	u := uint(i);
	if i < 0 {
		neg = true;
		u = -u;
	}

	// Assemble decimal in reverse order.
	var b [32]byte;
	bp := len(b);
	for ; u > 0; u /= 10 {
		bp--;
		b[bp] = byte(u%10) + '0'
	}
	if neg {	// add sign
		bp--;
		b[bp] = '-'
	}

	// BUG return string(b[bp:len(b)])
	return string((&b)[bp:len(b)])
}

export func itoa(i int) string {
	return itol(int64(i));
}
<|endoftext|>


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

package redis

import (
	"crypto/md5"
	"fmt"
	"time"

	"github.com/goharbor/harbor/src/lib/cache"
	libredis "github.com/goharbor/harbor/src/lib/redis"
	"github.com/gomodule/redigo/redis"
)

var _ cache.Cache = (*Cache)(nil)

// Cache redis cache
type Cache struct {
	opts *cache.Options
	pool *redis.Pool
}

// Contains returns true if key exists
func (c *Cache) Contains(key string) bool {
	reply, err := redis.Int(c.do("EXISTS", c.opts.Key(key)))
	if err != nil {
		return false
	}

	return reply == 1
}

// Delete delete item from cache by key
func (c *Cache) Delete(key string) error {
	_, err := c.do("DEL", c.opts.Key(key))
	return err
}

// Fetch retrieve the cached key value
func (c *Cache) Fetch(key string, value interface{}) error {
	data, err := redis.Bytes(c.do("GET", c.opts.Key(key)))
	if err != nil {
		// convert internal or Timeout error to be ErrNotFound
		// so that the caller can continue working without breaking
		return cache.ErrNotFound
	}

	if err := c.opts.Codec.Decode(data, value); err != nil {
		return fmt.Errorf("failed to decode cached value to dest, key %s, error: %v", key, err)
	}

	return nil
}

// Ping ping the cache
func (c *Cache) Ping() error {
	_, err := c.do("PING")
	return err
}

// Save cache the value by key
func (c *Cache) Save(key string, value interface{}, expiration ...time.Duration) error {
	data, err := c.opts.Codec.Encode(value)
	if err != nil {
		return fmt.Errorf("failed to encode value, key %s, error: %v", key, err)
	}

	args := []interface{}{c.opts.Key(key), data}

	var exp time.Duration
	if len(expiration) > 0 {
		exp = expiration[0]
	} else if c.opts.Expiration > 0 {
		exp = c.opts.Expiration
	}

	if exp > 0 {
		args = append(args, "EX", int64(exp/time.Second))
	}

	_, err = c.do("SET", args...)
	return err
}

func (c *Cache) do(commandName string, args ...interface{}) (reply interface{}, err error) {
	conn := c.pool.Get()
	defer conn.Close()

	return conn.Do(commandName, args...)
}

// New returns redis cache
func New(opts cache.Options) (cache.Cache, error) {
	if opts.Address == "" {
		opts.Address = "redis://localhost:6379/0"
	}

	name := fmt.Sprintf("%x", md5.Sum([]byte(opts.Address)))

	param := &libredis.PoolParam{
		PoolMaxIdle:           100,
		PoolMaxActive:         1000,
		PoolIdleTimeout:       10 * time.Minute,
		DialConnectionTimeout: time.Second,
		DialReadTimeout:       time.Second * 2,
		DialWriteTimeout:      time.Second * 5,
	}

	pool, err := libredis.GetRedisPool(name, opts.Address, param)
	if err != nil {
		return nil, err
	}

	return &Cache{opts: &opts, pool: pool}, nil
}

func init() {
	cache.Register(cache.Redis, New)
	cache.Register(cache.RedisSentinel, New)
}
<commit_msg>Fix semgrep use-of-weak-crypto error (#15784)<commit_after>// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package redis

import (
	"crypto/sha256"
	"fmt"
	"time"

	"github.com/goharbor/harbor/src/lib/cache"
	libredis "github.com/goharbor/harbor/src/lib/redis"
	"github.com/gomodule/redigo/redis"
)

var _ cache.Cache = (*Cache)(nil)

// Cache redis cache
type Cache struct {
	opts *cache.Options
	pool *redis.Pool
}

// Contains returns true if key exists
func (c *Cache) Contains(key string) bool {
	reply, err := redis.Int(c.do("EXISTS", c.opts.Key(key)))
	if err != nil {
		return false
	}

	return reply == 1
}

// Delete delete item from cache by key
func (c *Cache) Delete(key string) error {
	_, err := c.do("DEL", c.opts.Key(key))
	return err
}

// Fetch retrieve the cached key value
func (c *Cache) Fetch(key string, value interface{}) error {
	data, err := redis.Bytes(c.do("GET", c.opts.Key(key)))
	if err != nil {
		// convert internal or Timeout error to be ErrNotFound
		// so that the caller can continue working without breaking
		return cache.ErrNotFound
	}

	if err := c.opts.Codec.Decode(data, value); err != nil {
		return fmt.Errorf("failed to decode cached value to dest, key %s, error: %v", key, err)
	}

	return nil
}

// Ping ping the cache
func (c *Cache) Ping() error {
	_, err := c.do("PING")
	return err
}

// Save cache the value by key
func (c *Cache) Save(key string, value interface{}, expiration ...time.Duration) error {
	data, err := c.opts.Codec.Encode(value)
	if err != nil {
		return fmt.Errorf("failed to encode value, key %s, error: %v", key, err)
	}

	args := []interface{}{c.opts.Key(key), data}

	var exp time.Duration
	if len(expiration) > 0 {
		exp = expiration[0]
	} else if c.opts.Expiration > 0 {
		exp = c.opts.Expiration
	}

	if exp > 0 {
		args = append(args, "EX", int64(exp/time.Second))
	}

	_, err = c.do("SET", args...)
	return err
}

func (c *Cache) do(commandName string, args ...interface{}) (reply interface{}, err error) {
	conn := c.pool.Get()
	defer conn.Close()

	return conn.Do(commandName, args...)
}

// New returns redis cache
func New(opts cache.Options) (cache.Cache, error) {
	if opts.Address == "" {
		opts.Address = "redis://localhost:6379/0"
	}

	name := fmt.Sprintf("%x", sha256.Sum256([]byte(opts.Address)))

	param := &libredis.PoolParam{
		PoolMaxIdle:           100,
		PoolMaxActive:         1000,
		PoolIdleTimeout:       10 * time.Minute,
		DialConnectionTimeout: time.Second,
		DialReadTimeout:       time.Second * 2,
		DialWriteTimeout:      time.Second * 5,
	}

	pool, err := libredis.GetRedisPool(name, opts.Address, param)
	if err != nil {
		return nil, err
	}

	return &Cache{opts: &opts, pool: pool}, nil
}

func init() {
	cache.Register(cache.Redis, New)
	cache.Register(cache.RedisSentinel, New)
}
<|endoftext|>


<commit_before><commit_msg>Minimal status mutation change<commit_after><|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"testing"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/ec2"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

func TestAccAWSVpnConnection_basic(t *testing.T) {
	resource.Test(t, resource.TestCase{
		PreCheck:      func() { testAccPreCheck(t) },
		IDRefreshName: "aws_vpn_connection.foo",
		Providers:     testAccProviders,
		CheckDestroy:  testAccAwsVpnConnectionDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAwsVpnConnectionConfig,
				Check: resource.ComposeTestCheckFunc(
					testAccAwsVpnConnection(
						"aws_vpc.vpc",
						"aws_vpn_gateway.vpn_gateway",
						"aws_customer_gateway.customer_gateway",
						"aws_vpn_connection.foo",
					),
				),
			},
			{
				Config: testAccAwsVpnConnectionConfigUpdate,
				Check: resource.ComposeTestCheckFunc(
					testAccAwsVpnConnection(
						"aws_vpc.vpc",
						"aws_vpn_gateway.vpn_gateway",
						"aws_customer_gateway.customer_gateway",
						"aws_vpn_connection.foo",
					),
				),
			},
		},
	})
}

func TestAccAWSVpnConnection_withoutStaticRoutes(t *testing.T) {
	resource.Test(t, resource.TestCase{
		PreCheck:      func() { testAccPreCheck(t) },
		IDRefreshName: "aws_vpn_connection.foo",
		Providers:     testAccProviders,
		CheckDestroy:  testAccAwsVpnConnectionDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAwsVpnConnectionConfigUpdate,
				Check: resource.ComposeTestCheckFunc(
					testAccAwsVpnConnection(
						"aws_vpc.vpc",
						"aws_vpn_gateway.vpn_gateway",
						"aws_customer_gateway.customer_gateway",
						"aws_vpn_connection.foo",
					),
					resource.TestCheckResourceAttr("aws_vpn_connection.foo", "static_routes_only", "false"),
				),
			},
		},
	})
}

func testAccAwsVpnConnectionDestroy(s *terraform.State) error {
	conn := testAccProvider.Meta().(*AWSClient).ec2conn
	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_vpn_connection" {
			continue
		}

		resp, err := conn.DescribeVpnConnections(&ec2.DescribeVpnConnectionsInput{
			VpnConnectionIds: []*string{aws.String(rs.Primary.ID)},
		})

		if err != nil {
			if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidVpnConnectionID.NotFound" {
				// not found
				return nil
			}
			return err
		}

		var vpn *ec2.VpnConnection
		for _, v := range resp.VpnConnections {
			if v.VpnConnectionId != nil && *v.VpnConnectionId == rs.Primary.ID {
				vpn = v
			}
		}

		if vpn == nil {
			// vpn connection not found
			return nil
		}

		if vpn.State != nil && *vpn.State == "deleted" {
			return nil
		}

	}

	return nil
}

func testAccAwsVpnConnection(
	vpcResource string,
	vpnGatewayResource string,
	customerGatewayResource string,
	vpnConnectionResource string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[vpnConnectionResource]
		if !ok {
			return fmt.Errorf("Not found: %s", vpnConnectionResource)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No ID is set")
		}
		connection, ok := s.RootModule().Resources[vpnConnectionResource]
		if !ok {
			return fmt.Errorf("Not found: %s", vpnConnectionResource)
		}

		ec2conn := testAccProvider.Meta().(*AWSClient).ec2conn

		_, err := ec2conn.DescribeVpnConnections(&ec2.DescribeVpnConnectionsInput{
			VpnConnectionIds: []*string{aws.String(connection.Primary.ID)},
		})

		if err != nil {
			return err
		}

		return nil
	}
}

func TestAWSVpnConnection_xmlconfig(t *testing.T) {
	tunnelInfo, err := xmlConfigToTunnelInfo(testAccAwsVpnTunnelInfoXML)
	if err != nil {
		t.Fatalf("Error unmarshalling XML: %s", err)
	}
	if tunnelInfo.Tunnel1Address != "FIRST_ADDRESS" {
		t.Fatalf("First address from tunnel XML was incorrect.")
	}
	if tunnelInfo.Tunnel1PreSharedKey != "FIRST_KEY" {
		t.Fatalf("First key from tunnel XML was incorrect.")
	}
	if tunnelInfo.Tunnel2Address != "SECOND_ADDRESS" {
		t.Fatalf("Second address from tunnel XML was incorrect.")
	}
	if tunnelInfo.Tunnel2PreSharedKey != "SECOND_KEY" {
		t.Fatalf("Second key from tunnel XML was incorrect.")
	}
}

const testAccAwsVpnConnectionConfig = `
resource "aws_vpn_gateway" "vpn_gateway" {
  tags {
    Name = "vpn_gateway"
  }
}

resource "aws_customer_gateway" "customer_gateway" {
  bgp_asn = 65000
  ip_address = "178.0.0.1"
  type = "ipsec.1"
}

resource "aws_vpn_connection" "foo" {
  vpn_gateway_id = "${aws_vpn_gateway.vpn_gateway.id}"
  customer_gateway_id = "${aws_customer_gateway.customer_gateway.id}"
  type = "ipsec.1"
  static_routes_only = true
}
`

// Change static_routes_only to be false, forcing a refresh.
const testAccAwsVpnConnectionConfigUpdate = `
resource "aws_vpn_gateway" "vpn_gateway" {
  tags {
    Name = "vpn_gateway"
  }
}

resource "aws_customer_gateway" "customer_gateway" {
  bgp_asn = 65000
  ip_address = "178.0.0.1"
  type = "ipsec.1"
}

resource "aws_vpn_connection" "foo" {
  vpn_gateway_id = "${aws_vpn_gateway.vpn_gateway.id}"
  customer_gateway_id = "${aws_customer_gateway.customer_gateway.id}"
  type = "ipsec.1"
  static_routes_only = false
}
`

// Test our VPN tunnel config XML parsing
const testAccAwsVpnTunnelInfoXML = `
<vpn_connection id="vpn-abc123">
  <ipsec_tunnel>
    <vpn_gateway>
      <tunnel_outside_address>
        <ip_address>SECOND_ADDRESS</ip_address>
      </tunnel_outside_address>
    </vpn_gateway>
    <ike>
      <pre_shared_key>SECOND_KEY</pre_shared_key>
    </ike>
  </ipsec_tunnel>
  <ipsec_tunnel>
    <vpn_gateway>
      <tunnel_outside_address>
        <ip_address>FIRST_ADDRESS</ip_address>
      </tunnel_outside_address>
    </vpn_gateway>
    <ike>
      <pre_shared_key>FIRST_KEY</pre_shared_key>
    </ike>
  </ipsec_tunnel>
</vpn_connection>
`
<commit_msg>Add randomness to vpn connection test<commit_after>package aws

import (
	"fmt"
	"testing"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/ec2"

	"github.com/hashicorp/terraform/helper/acctest"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

func TestAccAWSVpnConnection_basic(t *testing.T) {
	rInt := acctest.RandInt()
	resource.Test(t, resource.TestCase{
		PreCheck:      func() { testAccPreCheck(t) },
		IDRefreshName: "aws_vpn_connection.foo",
		Providers:     testAccProviders,
		CheckDestroy:  testAccAwsVpnConnectionDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAwsVpnConnectionConfig,
				Check: resource.ComposeTestCheckFunc(
					testAccAwsVpnConnection(
						"aws_vpc.vpc",
						"aws_vpn_gateway.vpn_gateway",
						"aws_customer_gateway.customer_gateway",
						"aws_vpn_connection.foo",
					),
				),
			},
			{
				Config: testAccAwsVpnConnectionConfigUpdate(rInt),
				Check: resource.ComposeTestCheckFunc(
					testAccAwsVpnConnection(
						"aws_vpc.vpc",
						"aws_vpn_gateway.vpn_gateway",
						"aws_customer_gateway.customer_gateway",
						"aws_vpn_connection.foo",
					),
				),
			},
		},
	})
}

func TestAccAWSVpnConnection_withoutStaticRoutes(t *testing.T) {
	rInt := acctest.RandInt()
	resource.Test(t, resource.TestCase{
		PreCheck:      func() { testAccPreCheck(t) },
		IDRefreshName: "aws_vpn_connection.foo",
		Providers:     testAccProviders,
		CheckDestroy:  testAccAwsVpnConnectionDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAwsVpnConnectionConfigUpdate(rInt),
				Check: resource.ComposeTestCheckFunc(
					testAccAwsVpnConnection(
						"aws_vpc.vpc",
						"aws_vpn_gateway.vpn_gateway",
						"aws_customer_gateway.customer_gateway",
						"aws_vpn_connection.foo",
					),
					resource.TestCheckResourceAttr("aws_vpn_connection.foo", "static_routes_only", "false"),
				),
			},
		},
	})
}

func testAccAwsVpnConnectionDestroy(s *terraform.State) error {
	conn := testAccProvider.Meta().(*AWSClient).ec2conn
	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_vpn_connection" {
			continue
		}

		resp, err := conn.DescribeVpnConnections(&ec2.DescribeVpnConnectionsInput{
			VpnConnectionIds: []*string{aws.String(rs.Primary.ID)},
		})

		if err != nil {
			if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidVpnConnectionID.NotFound" {
				// not found
				return nil
			}
			return err
		}

		var vpn *ec2.VpnConnection
		for _, v := range resp.VpnConnections {
			if v.VpnConnectionId != nil && *v.VpnConnectionId == rs.Primary.ID {
				vpn = v
			}
		}

		if vpn == nil {
			// vpn connection not found
			return nil
		}

		if vpn.State != nil && *vpn.State == "deleted" {
			return nil
		}

	}

	return nil
}

func testAccAwsVpnConnection(
	vpcResource string,
	vpnGatewayResource string,
	customerGatewayResource string,
	vpnConnectionResource string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[vpnConnectionResource]
		if !ok {
			return fmt.Errorf("Not found: %s", vpnConnectionResource)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No ID is set")
		}
		connection, ok := s.RootModule().Resources[vpnConnectionResource]
		if !ok {
			return fmt.Errorf("Not found: %s", vpnConnectionResource)
		}

		ec2conn := testAccProvider.Meta().(*AWSClient).ec2conn

		_, err := ec2conn.DescribeVpnConnections(&ec2.DescribeVpnConnectionsInput{
			VpnConnectionIds: []*string{aws.String(connection.Primary.ID)},
		})

		if err != nil {
			return err
		}

		return nil
	}
}

func TestAWSVpnConnection_xmlconfig(t *testing.T) {
	tunnelInfo, err := xmlConfigToTunnelInfo(testAccAwsVpnTunnelInfoXML)
	if err != nil {
		t.Fatalf("Error unmarshalling XML: %s", err)
	}
	if tunnelInfo.Tunnel1Address != "FIRST_ADDRESS" {
		t.Fatalf("First address from tunnel XML was incorrect.")
	}
	if tunnelInfo.Tunnel1PreSharedKey != "FIRST_KEY" {
		t.Fatalf("First key from tunnel XML was incorrect.")
	}
	if tunnelInfo.Tunnel2Address != "SECOND_ADDRESS" {
		t.Fatalf("Second address from tunnel XML was incorrect.")
	}
	if tunnelInfo.Tunnel2PreSharedKey != "SECOND_KEY" {
		t.Fatalf("Second key from tunnel XML was incorrect.")
	}
}

const testAccAwsVpnConnectionConfig = `
	resource "aws_vpn_gateway" "vpn_gateway" {
	  tags {
	    Name = "vpn_gateway"
	  }
	}

	resource "aws_customer_gateway" "customer_gateway" {
	  bgp_asn = 65000
	  ip_address = "178.0.0.1"
	  type = "ipsec.1"
		tags {
			Name = "main-customer-gateway"
		}
	}

	resource "aws_vpn_connection" "foo" {
	  vpn_gateway_id = "${aws_vpn_gateway.vpn_gateway.id}"
	  customer_gateway_id = "${aws_customer_gateway.customer_gateway.id}"
	  type = "ipsec.1"
	  static_routes_only = true
	}
	`

// Change static_routes_only to be false, forcing a refresh.
func testAccAwsVpnConnectionConfigUpdate(rInt int) string {
	return fmt.Sprintf(`
	resource "aws_vpn_gateway" "vpn_gateway" {
	  tags {
	    Name = "vpn_gateway"
	  }
	}

	resource "aws_customer_gateway" "customer_gateway" {
	  bgp_asn = 65000
	  ip_address = "178.0.0.1"
	  type = "ipsec.1"
		tags {
	    Name = "main-customer-gateway-%d"
	  }
	}

	resource "aws_vpn_connection" "foo" {
	  vpn_gateway_id = "${aws_vpn_gateway.vpn_gateway.id}"
	  customer_gateway_id = "${aws_customer_gateway.customer_gateway.id}"
	  type = "ipsec.1"
	  static_routes_only = false
	}
	`, rInt)
}

// Test our VPN tunnel config XML parsing
const testAccAwsVpnTunnelInfoXML = `
<vpn_connection id="vpn-abc123">
  <ipsec_tunnel>
    <vpn_gateway>
      <tunnel_outside_address>
        <ip_address>SECOND_ADDRESS</ip_address>
      </tunnel_outside_address>
    </vpn_gateway>
    <ike>
      <pre_shared_key>SECOND_KEY</pre_shared_key>
    </ike>
  </ipsec_tunnel>
  <ipsec_tunnel>
    <vpn_gateway>
      <tunnel_outside_address>
        <ip_address>FIRST_ADDRESS</ip_address>
      </tunnel_outside_address>
    </vpn_gateway>
    <ike>
      <pre_shared_key>FIRST_KEY</pre_shared_key>
    </ike>
  </ipsec_tunnel>
</vpn_connection>
`
<|endoftext|>


<commit_before>/*
Copyright 2014 The Kubernetes Authors.

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

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

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

package validation

import (
	"fmt"
	"strings"

	apiequality "k8s.io/apimachinery/pkg/api/equality"
	"k8s.io/apimachinery/pkg/api/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	v1validation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/util/sets"
	"k8s.io/apimachinery/pkg/util/validation"
	"k8s.io/apimachinery/pkg/util/validation/field"
)

// FieldImmutableErrorMsg is a error message for field is immutable.
const FieldImmutableErrorMsg string = `field is immutable`

const TotalAnnotationSizeLimitB int = 256 * (1 << 10) // 256 kB

// BannedOwners is a black list of object that are not allowed to be owners.
var BannedOwners = map[schema.GroupVersionKind]struct{}{
	{Group: "", Version: "v1", Kind: "Event"}: {},
}

// ValidateAnnotations validates that a set of annotations are correctly defined.
func ValidateAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
	allErrs := field.ErrorList{}
	for k := range annotations {
		for _, msg := range validation.IsQualifiedName(strings.ToLower(k)) {
			allErrs = append(allErrs, field.Invalid(fldPath, k, msg))
		}
	}
	if err := ValidateAnnotationsSize(annotations); err != nil {
		allErrs = append(allErrs, field.TooLong(fldPath, "", TotalAnnotationSizeLimitB))
	}
	return allErrs
}

func ValidateAnnotationsSize(annotations map[string]string) error {
	var totalSize int64
	for k, v := range annotations {
		totalSize += (int64)(len(k)) + (int64)(len(v))
	}
	if totalSize > (int64)(TotalAnnotationSizeLimitB) {
		return fmt.Errorf("annotations size %d is larger than limit %d", totalSize, TotalAnnotationSizeLimitB)
	}
	return nil
}

func validateOwnerReference(ownerReference metav1.OwnerReference, fldPath *field.Path) field.ErrorList {
	allErrs := field.ErrorList{}
	gvk := schema.FromAPIVersionAndKind(ownerReference.APIVersion, ownerReference.Kind)
	// gvk.Group is empty for the legacy group.
	if len(gvk.Version) == 0 {
		allErrs = append(allErrs, field.Invalid(fldPath.Child("apiVersion"), ownerReference.APIVersion, "version must not be empty"))
	}
	if len(gvk.Kind) == 0 {
		allErrs = append(allErrs, field.Invalid(fldPath.Child("kind"), ownerReference.Kind, "kind must not be empty"))
	}
	if len(ownerReference.Name) == 0 {
		allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), ownerReference.Name, "name must not be empty"))
	}
	if len(ownerReference.UID) == 0 {
		allErrs = append(allErrs, field.Invalid(fldPath.Child("uid"), ownerReference.UID, "uid must not be empty"))
	}
	if _, ok := BannedOwners[gvk]; ok {
		allErrs = append(allErrs, field.Invalid(fldPath, ownerReference, fmt.Sprintf("%s is disallowed from being an owner", gvk)))
	}
	return allErrs
}

// ValidateOwnerReferences validates that a set of owner references are correctly defined.
func ValidateOwnerReferences(ownerReferences []metav1.OwnerReference, fldPath *field.Path) field.ErrorList {
	allErrs := field.ErrorList{}
	controllerName := ""
	for _, ref := range ownerReferences {
		allErrs = append(allErrs, validateOwnerReference(ref, fldPath)...)
		if ref.Controller != nil && *ref.Controller {
			if controllerName != "" {
				allErrs = append(allErrs, field.Invalid(fldPath, ownerReferences,
					fmt.Sprintf("Only one reference can have Controller set to true. Found \"true\" in references for %v and %v", controllerName, ref.Name)))
			} else {
				controllerName = ref.Name
			}
		}
	}
	return allErrs
}

// ValidateFinalizerName validates finalizer names.
func ValidateFinalizerName(stringValue string, fldPath *field.Path) field.ErrorList {
	allErrs := field.ErrorList{}
	for _, msg := range validation.IsQualifiedName(stringValue) {
		allErrs = append(allErrs, field.Invalid(fldPath, stringValue, msg))
	}

	return allErrs
}

// ValidateNoNewFinalizers validates the new finalizers has no new finalizers compare to old finalizers.
func ValidateNoNewFinalizers(newFinalizers []string, oldFinalizers []string, fldPath *field.Path) field.ErrorList {
	allErrs := field.ErrorList{}
	extra := sets.NewString(newFinalizers...).Difference(sets.NewString(oldFinalizers...))
	if len(extra) != 0 {
		allErrs = append(allErrs, field.Forbidden(fldPath, fmt.Sprintf("no new finalizers can be added if the object is being deleted, found new finalizers %#v", extra.List())))
	}
	return allErrs
}

// ValidateImmutableField validates the new value and the old value are deeply equal.
func ValidateImmutableField(newVal, oldVal interface{}, fldPath *field.Path) field.ErrorList {
	allErrs := field.ErrorList{}
	if !apiequality.Semantic.DeepEqual(oldVal, newVal) {
		allErrs = append(allErrs, field.Invalid(fldPath, newVal, FieldImmutableErrorMsg))
	}
	return allErrs
}

// ValidateObjectMeta validates an object's metadata on creation. It expects that name generation has already
// been performed.
// It doesn't return an error for rootscoped resources with namespace, because namespace should already be cleared before.
func ValidateObjectMeta(objMeta *metav1.ObjectMeta, requiresNamespace bool, nameFn ValidateNameFunc, fldPath *field.Path) field.ErrorList {
	metadata, err := meta.Accessor(objMeta)
	if err != nil {
		var allErrs field.ErrorList
		allErrs = append(allErrs, field.Invalid(fldPath, objMeta, err.Error()))
		return allErrs
	}
	return ValidateObjectMetaAccessor(metadata, requiresNamespace, nameFn, fldPath)
}

// ValidateObjectMetaAccessor validates an object's metadata on creation. It expects that name generation has already
// been performed.
// It doesn't return an error for rootscoped resources with namespace, because namespace should already be cleared before.
func ValidateObjectMetaAccessor(meta metav1.Object, requiresNamespace bool, nameFn ValidateNameFunc, fldPath *field.Path) field.ErrorList {
	var allErrs field.ErrorList

	if len(meta.GetGenerateName()) != 0 {
		for _, msg := range nameFn(meta.GetGenerateName(), true) {
			allErrs = append(allErrs, field.Invalid(fldPath.Child("generateName"), meta.GetGenerateName(), msg))
		}
	}
	// If the generated name validates, but the calculated value does not, it's a problem with generation, and we
	// report it here. This may confuse users, but indicates a programming bug and still must be validated.
	// If there are multiple fields out of which one is required then add an or as a separator
	if len(meta.GetName()) == 0 {
		allErrs = append(allErrs, field.Required(fldPath.Child("name"), "name or generateName is required"))
	} else {
		for _, msg := range nameFn(meta.GetName(), false) {
			allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), meta.GetName(), msg))
		}
	}
	if requiresNamespace {
		if len(meta.GetNamespace()) == 0 {
			allErrs = append(allErrs, field.Required(fldPath.Child("namespace"), ""))
		} else {
			for _, msg := range ValidateNamespaceName(meta.GetNamespace(), false) {
				allErrs = append(allErrs, field.Invalid(fldPath.Child("namespace"), meta.GetNamespace(), msg))
			}
		}
	} else {
		if len(meta.GetNamespace()) != 0 {
			allErrs = append(allErrs, field.Forbidden(fldPath.Child("namespace"), "not allowed on this type"))
		}
	}

	allErrs = append(allErrs, ValidateNonnegativeField(meta.GetGeneration(), fldPath.Child("generation"))...)
	allErrs = append(allErrs, v1validation.ValidateLabels(meta.GetLabels(), fldPath.Child("labels"))...)
	allErrs = append(allErrs, ValidateAnnotations(meta.GetAnnotations(), fldPath.Child("annotations"))...)
	allErrs = append(allErrs, ValidateOwnerReferences(meta.GetOwnerReferences(), fldPath.Child("ownerReferences"))...)
	allErrs = append(allErrs, ValidateFinalizers(meta.GetFinalizers(), fldPath.Child("finalizers"))...)
	allErrs = append(allErrs, v1validation.ValidateManagedFields(meta.GetManagedFields(), fldPath.Child("managedFields"))...)
	return allErrs
}

// ValidateFinalizers tests if the finalizers name are valid, and if there are conflicting finalizers.
func ValidateFinalizers(finalizers []string, fldPath *field.Path) field.ErrorList {
	allErrs := field.ErrorList{}
	hasFinalizerOrphanDependents := false
	hasFinalizerDeleteDependents := false
	for _, finalizer := range finalizers {
		allErrs = append(allErrs, ValidateFinalizerName(finalizer, fldPath)...)
		if finalizer == metav1.FinalizerOrphanDependents {
			hasFinalizerOrphanDependents = true
		}
		if finalizer == metav1.FinalizerDeleteDependents {
			hasFinalizerDeleteDependents = true
		}
	}
	if hasFinalizerDeleteDependents && hasFinalizerOrphanDependents {
		allErrs = append(allErrs, field.Invalid(fldPath, finalizers, fmt.Sprintf("finalizer %s and %s cannot be both set", metav1.FinalizerOrphanDependents, metav1.FinalizerDeleteDependents)))
	}
	return allErrs
}

// ValidateObjectMetaUpdate validates an object's metadata when updated.
func ValidateObjectMetaUpdate(newMeta, oldMeta *metav1.ObjectMeta, fldPath *field.Path) field.ErrorList {
	newMetadata, err := meta.Accessor(newMeta)
	if err != nil {
		allErrs := field.ErrorList{}
		allErrs = append(allErrs, field.Invalid(fldPath, newMeta, err.Error()))
		return allErrs
	}
	oldMetadata, err := meta.Accessor(oldMeta)
	if err != nil {
		allErrs := field.ErrorList{}
		allErrs = append(allErrs, field.Invalid(fldPath, oldMeta, err.Error()))
		return allErrs
	}
	return ValidateObjectMetaAccessorUpdate(newMetadata, oldMetadata, fldPath)
}

// ValidateObjectMetaAccessorUpdate validates an object's metadata when updated.
func ValidateObjectMetaAccessorUpdate(newMeta, oldMeta metav1.Object, fldPath *field.Path) field.ErrorList {
	var allErrs field.ErrorList

	// Finalizers cannot be added if the object is already being deleted.
	if oldMeta.GetDeletionTimestamp() != nil {
		allErrs = append(allErrs, ValidateNoNewFinalizers(newMeta.GetFinalizers(), oldMeta.GetFinalizers(), fldPath.Child("finalizers"))...)
	}

	// Reject updates that don't specify a resource version
	if len(newMeta.GetResourceVersion()) == 0 {
		allErrs = append(allErrs, field.Invalid(fldPath.Child("resourceVersion"), newMeta.GetResourceVersion(), "must be specified for an update"))
	}

	// Generation shouldn't be decremented
	if newMeta.GetGeneration() < oldMeta.GetGeneration() {
		allErrs = append(allErrs, field.Invalid(fldPath.Child("generation"), newMeta.GetGeneration(), "must not be decremented"))
	}

	allErrs = append(allErrs, ValidateImmutableField(newMeta.GetName(), oldMeta.GetName(), fldPath.Child("name"))...)
	allErrs = append(allErrs, ValidateImmutableField(newMeta.GetNamespace(), oldMeta.GetNamespace(), fldPath.Child("namespace"))...)
	allErrs = append(allErrs, ValidateImmutableField(newMeta.GetUID(), oldMeta.GetUID(), fldPath.Child("uid"))...)
	allErrs = append(allErrs, ValidateImmutableField(newMeta.GetCreationTimestamp(), oldMeta.GetCreationTimestamp(), fldPath.Child("creationTimestamp"))...)
	allErrs = append(allErrs, ValidateImmutableField(newMeta.GetDeletionTimestamp(), oldMeta.GetDeletionTimestamp(), fldPath.Child("deletionTimestamp"))...)
	allErrs = append(allErrs, ValidateImmutableField(newMeta.GetDeletionGracePeriodSeconds(), oldMeta.GetDeletionGracePeriodSeconds(), fldPath.Child("deletionGracePeriodSeconds"))...)

	allErrs = append(allErrs, v1validation.ValidateLabels(newMeta.GetLabels(), fldPath.Child("labels"))...)
	allErrs = append(allErrs, ValidateAnnotations(newMeta.GetAnnotations(), fldPath.Child("annotations"))...)
	allErrs = append(allErrs, ValidateOwnerReferences(newMeta.GetOwnerReferences(), fldPath.Child("ownerReferences"))...)
	allErrs = append(allErrs, v1validation.ValidateManagedFields(newMeta.GetManagedFields(), fldPath.Child("managedFields"))...)

	return allErrs
}
<commit_msg>clarify a comment on annotation key validation<commit_after>/*
Copyright 2014 The Kubernetes Authors.

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

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

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

package validation

import (
	"fmt"
	"strings"

	apiequality "k8s.io/apimachinery/pkg/api/equality"
	"k8s.io/apimachinery/pkg/api/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	v1validation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/util/sets"
	"k8s.io/apimachinery/pkg/util/validation"
	"k8s.io/apimachinery/pkg/util/validation/field"
)

// FieldImmutableErrorMsg is a error message for field is immutable.
const FieldImmutableErrorMsg string = `field is immutable`

const TotalAnnotationSizeLimitB int = 256 * (1 << 10) // 256 kB

// BannedOwners is a black list of object that are not allowed to be owners.
var BannedOwners = map[schema.GroupVersionKind]struct{}{
	{Group: "", Version: "v1", Kind: "Event"}: {},
}

// ValidateAnnotations validates that a set of annotations are correctly defined.
func ValidateAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
	allErrs := field.ErrorList{}
	for k := range annotations {
		// The rule is QualifiedName except that case doesn't matter, so convert to lowercase before checking.
		for _, msg := range validation.IsQualifiedName(strings.ToLower(k)) {
			allErrs = append(allErrs, field.Invalid(fldPath, k, msg))
		}
	}
	if err := ValidateAnnotationsSize(annotations); err != nil {
		allErrs = append(allErrs, field.TooLong(fldPath, "", TotalAnnotationSizeLimitB))
	}
	return allErrs
}

func ValidateAnnotationsSize(annotations map[string]string) error {
	var totalSize int64
	for k, v := range annotations {
		totalSize += (int64)(len(k)) + (int64)(len(v))
	}
	if totalSize > (int64)(TotalAnnotationSizeLimitB) {
		return fmt.Errorf("annotations size %d is larger than limit %d", totalSize, TotalAnnotationSizeLimitB)
	}
	return nil
}

func validateOwnerReference(ownerReference metav1.OwnerReference, fldPath *field.Path) field.ErrorList {
	allErrs := field.ErrorList{}
	gvk := schema.FromAPIVersionAndKind(ownerReference.APIVersion, ownerReference.Kind)
	// gvk.Group is empty for the legacy group.
	if len(gvk.Version) == 0 {
		allErrs = append(allErrs, field.Invalid(fldPath.Child("apiVersion"), ownerReference.APIVersion, "version must not be empty"))
	}
	if len(gvk.Kind) == 0 {
		allErrs = append(allErrs, field.Invalid(fldPath.Child("kind"), ownerReference.Kind, "kind must not be empty"))
	}
	if len(ownerReference.Name) == 0 {
		allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), ownerReference.Name, "name must not be empty"))
	}
	if len(ownerReference.UID) == 0 {
		allErrs = append(allErrs, field.Invalid(fldPath.Child("uid"), ownerReference.UID, "uid must not be empty"))
	}
	if _, ok := BannedOwners[gvk]; ok {
		allErrs = append(allErrs, field.Invalid(fldPath, ownerReference, fmt.Sprintf("%s is disallowed from being an owner", gvk)))
	}
	return allErrs
}

// ValidateOwnerReferences validates that a set of owner references are correctly defined.
func ValidateOwnerReferences(ownerReferences []metav1.OwnerReference, fldPath *field.Path) field.ErrorList {
	allErrs := field.ErrorList{}
	controllerName := ""
	for _, ref := range ownerReferences {
		allErrs = append(allErrs, validateOwnerReference(ref, fldPath)...)
		if ref.Controller != nil && *ref.Controller {
			if controllerName != "" {
				allErrs = append(allErrs, field.Invalid(fldPath, ownerReferences,
					fmt.Sprintf("Only one reference can have Controller set to true. Found \"true\" in references for %v and %v", controllerName, ref.Name)))
			} else {
				controllerName = ref.Name
			}
		}
	}
	return allErrs
}

// ValidateFinalizerName validates finalizer names.
func ValidateFinalizerName(stringValue string, fldPath *field.Path) field.ErrorList {
	allErrs := field.ErrorList{}
	for _, msg := range validation.IsQualifiedName(stringValue) {
		allErrs = append(allErrs, field.Invalid(fldPath, stringValue, msg))
	}

	return allErrs
}

// ValidateNoNewFinalizers validates the new finalizers has no new finalizers compare to old finalizers.
func ValidateNoNewFinalizers(newFinalizers []string, oldFinalizers []string, fldPath *field.Path) field.ErrorList {
	allErrs := field.ErrorList{}
	extra := sets.NewString(newFinalizers...).Difference(sets.NewString(oldFinalizers...))
	if len(extra) != 0 {
		allErrs = append(allErrs, field.Forbidden(fldPath, fmt.Sprintf("no new finalizers can be added if the object is being deleted, found new finalizers %#v", extra.List())))
	}
	return allErrs
}

// ValidateImmutableField validates the new value and the old value are deeply equal.
func ValidateImmutableField(newVal, oldVal interface{}, fldPath *field.Path) field.ErrorList {
	allErrs := field.ErrorList{}
	if !apiequality.Semantic.DeepEqual(oldVal, newVal) {
		allErrs = append(allErrs, field.Invalid(fldPath, newVal, FieldImmutableErrorMsg))
	}
	return allErrs
}

// ValidateObjectMeta validates an object's metadata on creation. It expects that name generation has already
// been performed.
// It doesn't return an error for rootscoped resources with namespace, because namespace should already be cleared before.
func ValidateObjectMeta(objMeta *metav1.ObjectMeta, requiresNamespace bool, nameFn ValidateNameFunc, fldPath *field.Path) field.ErrorList {
	metadata, err := meta.Accessor(objMeta)
	if err != nil {
		var allErrs field.ErrorList
		allErrs = append(allErrs, field.Invalid(fldPath, objMeta, err.Error()))
		return allErrs
	}
	return ValidateObjectMetaAccessor(metadata, requiresNamespace, nameFn, fldPath)
}

// ValidateObjectMetaAccessor validates an object's metadata on creation. It expects that name generation has already
// been performed.
// It doesn't return an error for rootscoped resources with namespace, because namespace should already be cleared before.
func ValidateObjectMetaAccessor(meta metav1.Object, requiresNamespace bool, nameFn ValidateNameFunc, fldPath *field.Path) field.ErrorList {
	var allErrs field.ErrorList

	if len(meta.GetGenerateName()) != 0 {
		for _, msg := range nameFn(meta.GetGenerateName(), true) {
			allErrs = append(allErrs, field.Invalid(fldPath.Child("generateName"), meta.GetGenerateName(), msg))
		}
	}
	// If the generated name validates, but the calculated value does not, it's a problem with generation, and we
	// report it here. This may confuse users, but indicates a programming bug and still must be validated.
	// If there are multiple fields out of which one is required then add an or as a separator
	if len(meta.GetName()) == 0 {
		allErrs = append(allErrs, field.Required(fldPath.Child("name"), "name or generateName is required"))
	} else {
		for _, msg := range nameFn(meta.GetName(), false) {
			allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), meta.GetName(), msg))
		}
	}
	if requiresNamespace {
		if len(meta.GetNamespace()) == 0 {
			allErrs = append(allErrs, field.Required(fldPath.Child("namespace"), ""))
		} else {
			for _, msg := range ValidateNamespaceName(meta.GetNamespace(), false) {
				allErrs = append(allErrs, field.Invalid(fldPath.Child("namespace"), meta.GetNamespace(), msg))
			}
		}
	} else {
		if len(meta.GetNamespace()) != 0 {
			allErrs = append(allErrs, field.Forbidden(fldPath.Child("namespace"), "not allowed on this type"))
		}
	}

	allErrs = append(allErrs, ValidateNonnegativeField(meta.GetGeneration(), fldPath.Child("generation"))...)
	allErrs = append(allErrs, v1validation.ValidateLabels(meta.GetLabels(), fldPath.Child("labels"))...)
	allErrs = append(allErrs, ValidateAnnotations(meta.GetAnnotations(), fldPath.Child("annotations"))...)
	allErrs = append(allErrs, ValidateOwnerReferences(meta.GetOwnerReferences(), fldPath.Child("ownerReferences"))...)
	allErrs = append(allErrs, ValidateFinalizers(meta.GetFinalizers(), fldPath.Child("finalizers"))...)
	allErrs = append(allErrs, v1validation.ValidateManagedFields(meta.GetManagedFields(), fldPath.Child("managedFields"))...)
	return allErrs
}

// ValidateFinalizers tests if the finalizers name are valid, and if there are conflicting finalizers.
func ValidateFinalizers(finalizers []string, fldPath *field.Path) field.ErrorList {
	allErrs := field.ErrorList{}
	hasFinalizerOrphanDependents := false
	hasFinalizerDeleteDependents := false
	for _, finalizer := range finalizers {
		allErrs = append(allErrs, ValidateFinalizerName(finalizer, fldPath)...)
		if finalizer == metav1.FinalizerOrphanDependents {
			hasFinalizerOrphanDependents = true
		}
		if finalizer == metav1.FinalizerDeleteDependents {
			hasFinalizerDeleteDependents = true
		}
	}
	if hasFinalizerDeleteDependents && hasFinalizerOrphanDependents {
		allErrs = append(allErrs, field.Invalid(fldPath, finalizers, fmt.Sprintf("finalizer %s and %s cannot be both set", metav1.FinalizerOrphanDependents, metav1.FinalizerDeleteDependents)))
	}
	return allErrs
}

// ValidateObjectMetaUpdate validates an object's metadata when updated.
func ValidateObjectMetaUpdate(newMeta, oldMeta *metav1.ObjectMeta, fldPath *field.Path) field.ErrorList {
	newMetadata, err := meta.Accessor(newMeta)
	if err != nil {
		allErrs := field.ErrorList{}
		allErrs = append(allErrs, field.Invalid(fldPath, newMeta, err.Error()))
		return allErrs
	}
	oldMetadata, err := meta.Accessor(oldMeta)
	if err != nil {
		allErrs := field.ErrorList{}
		allErrs = append(allErrs, field.Invalid(fldPath, oldMeta, err.Error()))
		return allErrs
	}
	return ValidateObjectMetaAccessorUpdate(newMetadata, oldMetadata, fldPath)
}

// ValidateObjectMetaAccessorUpdate validates an object's metadata when updated.
func ValidateObjectMetaAccessorUpdate(newMeta, oldMeta metav1.Object, fldPath *field.Path) field.ErrorList {
	var allErrs field.ErrorList

	// Finalizers cannot be added if the object is already being deleted.
	if oldMeta.GetDeletionTimestamp() != nil {
		allErrs = append(allErrs, ValidateNoNewFinalizers(newMeta.GetFinalizers(), oldMeta.GetFinalizers(), fldPath.Child("finalizers"))...)
	}

	// Reject updates that don't specify a resource version
	if len(newMeta.GetResourceVersion()) == 0 {
		allErrs = append(allErrs, field.Invalid(fldPath.Child("resourceVersion"), newMeta.GetResourceVersion(), "must be specified for an update"))
	}

	// Generation shouldn't be decremented
	if newMeta.GetGeneration() < oldMeta.GetGeneration() {
		allErrs = append(allErrs, field.Invalid(fldPath.Child("generation"), newMeta.GetGeneration(), "must not be decremented"))
	}

	allErrs = append(allErrs, ValidateImmutableField(newMeta.GetName(), oldMeta.GetName(), fldPath.Child("name"))...)
	allErrs = append(allErrs, ValidateImmutableField(newMeta.GetNamespace(), oldMeta.GetNamespace(), fldPath.Child("namespace"))...)
	allErrs = append(allErrs, ValidateImmutableField(newMeta.GetUID(), oldMeta.GetUID(), fldPath.Child("uid"))...)
	allErrs = append(allErrs, ValidateImmutableField(newMeta.GetCreationTimestamp(), oldMeta.GetCreationTimestamp(), fldPath.Child("creationTimestamp"))...)
	allErrs = append(allErrs, ValidateImmutableField(newMeta.GetDeletionTimestamp(), oldMeta.GetDeletionTimestamp(), fldPath.Child("deletionTimestamp"))...)
	allErrs = append(allErrs, ValidateImmutableField(newMeta.GetDeletionGracePeriodSeconds(), oldMeta.GetDeletionGracePeriodSeconds(), fldPath.Child("deletionGracePeriodSeconds"))...)

	allErrs = append(allErrs, v1validation.ValidateLabels(newMeta.GetLabels(), fldPath.Child("labels"))...)
	allErrs = append(allErrs, ValidateAnnotations(newMeta.GetAnnotations(), fldPath.Child("annotations"))...)
	allErrs = append(allErrs, ValidateOwnerReferences(newMeta.GetOwnerReferences(), fldPath.Child("ownerReferences"))...)
	allErrs = append(allErrs, v1validation.ValidateManagedFields(newMeta.GetManagedFields(), fldPath.Child("managedFields"))...)

	return allErrs
}
<|endoftext|>


<commit_before>package client

import (
	"fmt"
	"os"
	"strconv"

	"go.pedge.io/proto/version"
	"google.golang.org/grpc"

	"github.com/pachyderm/pachyderm/src/client/pfs"
	"github.com/pachyderm/pachyderm/src/client/pps"
)

const (
	// MajorVersion is the current major version for pachyderm.
	MajorVersion = 1
	// MinorVersion is the current minor version for pachyderm.
	MinorVersion = 0
	// AdditionalVersion will be "dev" is this is a development branch, "" otherwise.
	AdditionalVersion = ""
)

var (
	// Version is the current version for pachyderm.
	Version = &protoversion.Version{
		Major:      MajorVersion,
		Minor:      MinorVersion,
		Micro:      getMicroVersion(),
		Additional: AdditionalVersion,
	}
)

type PfsAPIClient pfs.APIClient
type PpsAPIClient pps.APIClient

type APIClient struct {
	PfsAPIClient
	PpsAPIClient
}

func NewFromAddress(pachAddr string) (*APIClient, error) {
	clientConn, err := grpc.Dial(pachAddr, grpc.WithInsecure())
	if err != nil {
		return nil, err
	}

	return &APIClient{
		pfs.NewAPIClient(clientConn),
		pps.NewAPIClient(clientConn),
	}, nil
}

func New() (*APIClient, error) {
	pachAddr := os.Getenv("PACHD_PORT_650_TCP_ADDR")

	if pachAddr == "" {
		return nil, fmt.Errorf("PACHD_PORT_650_TCP_ADDR not set")
	}

	return NewFromAddress(fmt.Sprintf("%v:650", pachAddr))
}

func getMicroVersion() (v uint32) {
	value := os.Getenv("BUILD_NUMBER")
	if value == "" {
		v = 0
	} else {
		number, err := strconv.Atoi(value)
		if err != nil {
			panic(fmt.Sprintf("Invalid build number provided via BUILD_NUMBER env variable: (%v)\n", value))
		}
		v = uint32(number)
	}
	return v
}
<commit_msg>Rename version env variable to be namespaced for pachyderm<commit_after>package client

import (
	"fmt"
	"os"
	"strconv"

	"go.pedge.io/proto/version"
	"google.golang.org/grpc"

	"github.com/pachyderm/pachyderm/src/client/pfs"
	"github.com/pachyderm/pachyderm/src/client/pps"
)

const (
	// MajorVersion is the current major version for pachyderm.
	MajorVersion = 1
	// MinorVersion is the current minor version for pachyderm.
	MinorVersion = 0
	// AdditionalVersion will be "dev" is this is a development branch, "" otherwise.
	AdditionalVersion = ""
)

var (
	// Version is the current version for pachyderm.
	Version = &protoversion.Version{
		Major:      MajorVersion,
		Minor:      MinorVersion,
		Micro:      getMicroVersion(),
		Additional: AdditionalVersion,
	}
)

type PfsAPIClient pfs.APIClient
type PpsAPIClient pps.APIClient

type APIClient struct {
	PfsAPIClient
	PpsAPIClient
}

func NewFromAddress(pachAddr string) (*APIClient, error) {
	clientConn, err := grpc.Dial(pachAddr, grpc.WithInsecure())
	if err != nil {
		return nil, err
	}

	return &APIClient{
		pfs.NewAPIClient(clientConn),
		pps.NewAPIClient(clientConn),
	}, nil
}

func New() (*APIClient, error) {
	pachAddr := os.Getenv("PACHD_PORT_650_TCP_ADDR")

	if pachAddr == "" {
		return nil, fmt.Errorf("PACHD_PORT_650_TCP_ADDR not set")
	}

	return NewFromAddress(fmt.Sprintf("%v:650", pachAddr))
}

func getMicroVersion() (v uint32) {
	value := os.Getenv("PACH_BUILD_NUMBER")
	if value == "" {
		v = 0
	} else {
		number, err := strconv.Atoi(value)
		if err != nil {
			panic(fmt.Sprintf("Invalid build number provided via PACH_BUILD_NUMBER env variable: (%v)\n", value))
		}
		v = uint32(number)
	}
	return v
}
<|endoftext|>