<commit_before>package tonic

import (
	"encoding"
	"fmt"
	"io"
	"net/http"
	"reflect"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	validator "gopkg.in/go-playground/validator.v9"
)

// MaxBodyBytes is the maximum allowed size of a request body in bytes.
const MaxBodyBytes = 256 * 1024

// Fields tags used by tonic.
const (
	QueryTag      = "query"
	PathTag       = "path"
	HeaderTag     = "header"
	EnumTag       = "enum"
	RequiredTag   = "required"
	DefaultTag    = "default"
	ValidationTag = "validate"
)

const (
	defaultMediaType    = "application/json"
	tonicRoutesInfos    = "_tonic_route_infos"
	tonicWantRouteInfos = "_tonic_want_route_infos"
)

var (
	errorHook  ErrorHook  = DefaultErrorHook
	bindHook   BindHook   = DefaultBindingHook
	renderHook RenderHook = DefaultRenderHook
	execHook   ExecHook   = DefaultExecHook

	mediaType = defaultMediaType

	routes  = make(map[string]*Route)
	funcs   = make(map[string]struct{})
	funcsMu = sync.Mutex{}
)

// BindHook is the hook called by the wrapping gin-handler when
// binding an incoming request to the tonic-handler's input object.
type BindHook func(*gin.Context, interface{}) error

// RenderHook is the last hook called by the wrapping gin-handler
// before returning. It takes the Gin context, the HTTP status code
// and the response payload as parameters.
// Its role is to render the payload to the client to the
// proper format.
type RenderHook func(*gin.Context, int, interface{})

// ErrorHook lets you interpret errors returned by your handlers.
// After analysis, the hook should return a suitable http status code
// and and error payload.
// This lets you deeply inspect custom error types.
type ErrorHook func(*gin.Context, error) (int, interface{})

// An ExecHook is the func called to handle a request.
// The default ExecHook simply calle the wrapping gin-handler
// with the gin context.
type ExecHook func(*gin.Context, gin.HandlerFunc, string)

// DefaultErrorHook is the default error hook.
// It returns a StatusBadRequest with a payload containing
// the error message.
func DefaultErrorHook(c *gin.Context, e error) (int, interface{}) {
	return http.StatusBadRequest, gin.H{
		"error": e.Error(),
	}
}

// DefaultBindingHook is the default binding hook.
// It uses Gin JSON binding to bind the body parameters of the request
// to the input object of the handler.
// Ir teturns an error if Gin binding fails.
func DefaultBindingHook(c *gin.Context, i interface{}) error {
	c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, MaxBodyBytes)
	if c.Request.ContentLength == 0 || c.Request.Method == http.MethodGet {
		return nil
	}
	if err := c.ShouldBindWith(i, binding.JSON); err != nil && err != io.EOF {
		return fmt.Errorf("error parsing request body: %s", err.Error())
	}
	return nil
}

// DefaultRenderHook is the default render hook.
// It marshals the payload to JSON, or returns an empty body if the payload is nil.
// If Gin is running in debug mode, the marshalled JSON is indented.
func DefaultRenderHook(c *gin.Context, status int, payload interface{}) {
	if payload != nil {
		if gin.IsDebugging() {
			c.IndentedJSON(status, payload)
		} else {
			c.JSON(status, payload)
		}
	} else {
		c.String(status, "")
	}
}

// DefaultExecHook is the default exec hook.
// It simply executes the wrapping gin-handler with
// the given context.
func DefaultExecHook(c *gin.Context, h gin.HandlerFunc, fname string) {
	h(c)
}

// GetRoutes returns the routes handled by a tonic-enabled handler.
func GetRoutes() map[string]*Route {
	return routes
}

// MediaType returns the current media type (MIME)
// used by the actual render hook.
func MediaType() string {
	return defaultMediaType
}

// GetErrorHook returns the current error hook.
func GetErrorHook() ErrorHook {
	return errorHook
}

// SetErrorHook sets the given hook as the
// default error handling hook.
func SetErrorHook(eh ErrorHook) {
	if eh != nil {
		errorHook = eh
	}
}

// GetBindHook returns the current bind hook.
func GetBindHook() BindHook {
	return bindHook
}

// SetBindHook sets the given hook as the
// default binding hook.
func SetBindHook(bh BindHook) {
	if bh != nil {
		bindHook = bh
	}
}

// GetRenderHook returns the current render hook.
func GetRenderHook() RenderHook {
	return renderHook
}

// SetRenderHook sets the given hook as the default
// rendering hook. The media type is used to generate
// the OpenAPI specification.
func SetRenderHook(rh RenderHook, mt string) {
	if rh != nil {
		renderHook = rh
	}
	if mt != "" {
		mediaType = mt
	}
}

// SetExecHook sets the given hook as the
// default execution hook.
func SetExecHook(eh ExecHook) {
	if eh != nil {
		execHook = eh
	}
}

// GetExecHook returns the current execution hook.
func GetExecHook() ExecHook {
	return execHook
}

// Description set the description of a route.
func Description(s string) func(*Route) {
	return func(r *Route) {
		r.description = s
	}
}

// Summary set the summary of a route.
func Summary(s string) func(*Route) {
	return func(r *Route) {
		r.summary = s
	}
}

// Deprecated set the deprecated flag of a route.
func Deprecated(b bool) func(*Route) {
	return func(r *Route) {
		r.deprecated = b
	}
}

// BindError is an error type returned when tonic fails
// to bind parameters, to differentiate from errors returned
// by the handlers.
type BindError struct {
	validationErr error
	message       string
	typ           reflect.Type
	field         string
}

// Error implements the builtin error interface for BindError.
func (be BindError) Error() string {
	if be.field != "" && be.typ != nil {
		return fmt.Sprintf(
			"binding error on field '%s' of type '%s': %s",
			be.field,
			be.typ.Name(),
			be.message,
		)
	}
	return fmt.Sprintf("binding error: %s", be.message)
}

// ValidationErrors returns the errors from the validate process.
func (be BindError) ValidationErrors() validator.ValidationErrors {
	switch t := be.validationErr.(type) {
	case validator.ValidationErrors:
		return t
	}
	return nil
}

// An extractorFunc extracts data from a gin context according to
// parameters specified in a field tag.
type extractor func(*gin.Context, string) (string, []string, error)

// extractQuery is an extractor tgat operated on the query
// parameters of a request.
func extractQuery(c *gin.Context, tag string) (string, []string, error) {
	name, required, defaultVal, err := parseTagKey(tag)
	if err != nil {
		return "", nil, err
	}

	rawQ := c.Request.URL.Query()[name]

	// delete empty elements so default+required will play nice together
	// append to a new collection to preserve order without too much copying
	q := make([]string, 0, len(rawQ))
	for i := range rawQ {
		if rawQ[i] != "" {
			q = append(q, rawQ[i])
		}
	}

	// XXX: deprecated, use of "default" tag is preferred
	if len(q) == 0 && defaultVal != "" {
		return name, []string{defaultVal}, nil
	}
	// XXX: deprecated, use of "validate" tag is preferred
	if len(q) == 0 && required {
		return "", nil, fmt.Errorf("missing query parameter: %s", name)
	}
	return name, q, nil
}

// extractPath is an extractor that operates on the path
// parameters of a request.
func extractPath(c *gin.Context, tag string) (string, []string, error) {
	name, required, defaultVal, err := parseTagKey(tag)
	if err != nil {
		return "", nil, err
	}
	p := c.Param(name)

	// XXX: deprecated, use of "default" tag is preferred
	if p == "" && defaultVal != "" {
		return name, []string{defaultVal}, nil
	}
	// XXX: deprecated, use of "validate" tag is preferred
	if p == "" && required {
		return "", nil, fmt.Errorf("missing path parameter: %s", name)
	}

	return name, []string{p}, nil
}

// extractHeader is an extractor that operates on the headers
// of a request.
func extractHeader(c *gin.Context, tag string) (string, []string, error) {
	name, required, defaultVal, err := parseTagKey(tag)
	if err != nil {
		return "", nil, err
	}
	header := c.GetHeader(name)

	// XXX: deprecated, use of "default" tag is preferred
	if header == "" && defaultVal != "" {
		return name, []string{defaultVal}, nil
	}
	// XXX: deprecated, use of "validate" tag is preferred
	if required && header == "" {
		return "", nil, fmt.Errorf("missing header parameter: %s", name)
	}
	return name, []string{header}, nil
}

// Public signature does not expose "required" and "default" because
// they are deprecated in favor of the "validate" and "default" tags
func parseTagKey(tag string) (string, bool, string, error) {
	parts := strings.Split(tag, ",")
	if len(parts) == 0 {
		return "", false, "", fmt.Errorf("empty tag")
	}
	name, options := parts[0], parts[1:]

	var defaultVal string

	// XXX: deprecated, required + default are kept here for backwards compatibility
	// use of "default" and "validate" tags is preferred
	// Iterate through the tag options to
	// find the required key.
	var required bool
	for _, o := range options {
		o = strings.TrimSpace(o)
		if o == RequiredTag {
			required = true
		} else if strings.HasPrefix(o, fmt.Sprintf("%s=", DefaultTag)) {
			defaultVal = strings.TrimPrefix(o, fmt.Sprintf("%s=", DefaultTag))
		} else {
			return "", false, "", fmt.Errorf("malformed tag for param '%s': unknown option '%s'", name, o)
		}
	}
	return name, required, defaultVal, nil
}

// ParseTagKey parses the given struct tag key and return the
// name of the field
func ParseTagKey(tag string) (string, error) {
	s, _, _, err := parseTagKey(tag)
	return s, err
}

// bindStringValue converts and bind the value s
// to the the reflected value v.
func bindStringValue(s string, v reflect.Value) error {
	// Ensure that the reflected value is addressable
	// and wasn't obtained by the use of an unexported
	// struct field, or calling a setter will panic.
	if !v.CanSet() {
		return fmt.Errorf("unaddressable value: %v", v)
	}
	i := reflect.New(v.Type()).Interface()

	// If the value implements the encoding.TextUnmarshaler
	// interface, bind the returned string representation.
	if unmarshaler, ok := i.(encoding.TextUnmarshaler); ok {
		if err := unmarshaler.UnmarshalText([]byte(s)); err != nil {
			return err
		}
		v.Set(reflect.Indirect(reflect.ValueOf(unmarshaler)))
		return nil
	}
	// Handle time.Duration.
	if _, ok := i.(time.Duration); ok {
		d, err := time.ParseDuration(s)
		if err != nil {
			return err
		}
		v.Set(reflect.ValueOf(d))
	}
	// Switch over the kind of the reflected value
	// and convert the string to the proper type.
	switch v.Kind() {
	case reflect.String:
		v.SetString(s)
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		i, err := strconv.ParseInt(s, 10, v.Type().Bits())
		if err != nil {
			return err
		}
		v.SetInt(i)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		i, err := strconv.ParseUint(s, 10, v.Type().Bits())
		if err != nil {
			return err
		}
		v.SetUint(i)
	case reflect.Bool:
		b, err := strconv.ParseBool(s)
		if err != nil {
			return err
		}
		v.SetBool(b)
	case reflect.Float32, reflect.Float64:
		i, err := strconv.ParseFloat(s, v.Type().Bits())
		if err != nil {
			return err
		}
		v.SetFloat(i)
	default:
		return fmt.Errorf("unsupported parameter type: %v", v.Kind())
	}
	return nil
}
<commit_msg>Use ResponseWriter status if set in DefaultRenderHook.<commit_after>package tonic

import (
	"encoding"
	"fmt"
	"io"
	"net/http"
	"reflect"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	validator "gopkg.in/go-playground/validator.v9"
)

// MaxBodyBytes is the maximum allowed size of a request body in bytes.
const MaxBodyBytes = 256 * 1024

// Fields tags used by tonic.
const (
	QueryTag      = "query"
	PathTag       = "path"
	HeaderTag     = "header"
	EnumTag       = "enum"
	RequiredTag   = "required"
	DefaultTag    = "default"
	ValidationTag = "validate"
)

const (
	defaultMediaType    = "application/json"
	tonicRoutesInfos    = "_tonic_route_infos"
	tonicWantRouteInfos = "_tonic_want_route_infos"
)

var (
	errorHook  ErrorHook  = DefaultErrorHook
	bindHook   BindHook   = DefaultBindingHook
	renderHook RenderHook = DefaultRenderHook
	execHook   ExecHook   = DefaultExecHook

	mediaType = defaultMediaType

	routes  = make(map[string]*Route)
	funcs   = make(map[string]struct{})
	funcsMu = sync.Mutex{}
)

// BindHook is the hook called by the wrapping gin-handler when
// binding an incoming request to the tonic-handler's input object.
type BindHook func(*gin.Context, interface{}) error

// RenderHook is the last hook called by the wrapping gin-handler
// before returning. It takes the Gin context, the HTTP status code
// and the response payload as parameters.
// Its role is to render the payload to the client to the
// proper format.
type RenderHook func(*gin.Context, int, interface{})

// ErrorHook lets you interpret errors returned by your handlers.
// After analysis, the hook should return a suitable http status code
// and and error payload.
// This lets you deeply inspect custom error types.
type ErrorHook func(*gin.Context, error) (int, interface{})

// An ExecHook is the func called to handle a request.
// The default ExecHook simply calle the wrapping gin-handler
// with the gin context.
type ExecHook func(*gin.Context, gin.HandlerFunc, string)

// DefaultErrorHook is the default error hook.
// It returns a StatusBadRequest with a payload containing
// the error message.
func DefaultErrorHook(c *gin.Context, e error) (int, interface{}) {
	return http.StatusBadRequest, gin.H{
		"error": e.Error(),
	}
}

// DefaultBindingHook is the default binding hook.
// It uses Gin JSON binding to bind the body parameters of the request
// to the input object of the handler.
// Ir teturns an error if Gin binding fails.
func DefaultBindingHook(c *gin.Context, i interface{}) error {
	c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, MaxBodyBytes)
	if c.Request.ContentLength == 0 || c.Request.Method == http.MethodGet {
		return nil
	}
	if err := c.ShouldBindWith(i, binding.JSON); err != nil && err != io.EOF {
		return fmt.Errorf("error parsing request body: %s", err.Error())
	}
	return nil
}

// DefaultRenderHook is the default render hook.
// It marshals the payload to JSON, or returns an empty body if the payload is nil.
// If Gin is running in debug mode, the marshalled JSON is indented.
func DefaultRenderHook(c *gin.Context, statusCode int, payload interface{}) {
	var status int
	if c.Writer.Written() {
		status = c.Writer.Status()
	} else {
		status = statusCode
	}
	if payload != nil {
		if gin.IsDebugging() {
			c.IndentedJSON(status, payload)
		} else {
			c.JSON(status, payload)
		}
	} else {
		c.String(status, "")
	}
}

// DefaultExecHook is the default exec hook.
// It simply executes the wrapping gin-handler with
// the given context.
func DefaultExecHook(c *gin.Context, h gin.HandlerFunc, fname string) {
	h(c)
}

// GetRoutes returns the routes handled by a tonic-enabled handler.
func GetRoutes() map[string]*Route {
	return routes
}

// MediaType returns the current media type (MIME)
// used by the actual render hook.
func MediaType() string {
	return defaultMediaType
}

// GetErrorHook returns the current error hook.
func GetErrorHook() ErrorHook {
	return errorHook
}

// SetErrorHook sets the given hook as the
// default error handling hook.
func SetErrorHook(eh ErrorHook) {
	if eh != nil {
		errorHook = eh
	}
}

// GetBindHook returns the current bind hook.
func GetBindHook() BindHook {
	return bindHook
}

// SetBindHook sets the given hook as the
// default binding hook.
func SetBindHook(bh BindHook) {
	if bh != nil {
		bindHook = bh
	}
}

// GetRenderHook returns the current render hook.
func GetRenderHook() RenderHook {
	return renderHook
}

// SetRenderHook sets the given hook as the default
// rendering hook. The media type is used to generate
// the OpenAPI specification.
func SetRenderHook(rh RenderHook, mt string) {
	if rh != nil {
		renderHook = rh
	}
	if mt != "" {
		mediaType = mt
	}
}

// SetExecHook sets the given hook as the
// default execution hook.
func SetExecHook(eh ExecHook) {
	if eh != nil {
		execHook = eh
	}
}

// GetExecHook returns the current execution hook.
func GetExecHook() ExecHook {
	return execHook
}

// Description set the description of a route.
func Description(s string) func(*Route) {
	return func(r *Route) {
		r.description = s
	}
}

// Summary set the summary of a route.
func Summary(s string) func(*Route) {
	return func(r *Route) {
		r.summary = s
	}
}

// Deprecated set the deprecated flag of a route.
func Deprecated(b bool) func(*Route) {
	return func(r *Route) {
		r.deprecated = b
	}
}

// BindError is an error type returned when tonic fails
// to bind parameters, to differentiate from errors returned
// by the handlers.
type BindError struct {
	validationErr error
	message       string
	typ           reflect.Type
	field         string
}

// Error implements the builtin error interface for BindError.
func (be BindError) Error() string {
	if be.field != "" && be.typ != nil {
		return fmt.Sprintf(
			"binding error on field '%s' of type '%s': %s",
			be.field,
			be.typ.Name(),
			be.message,
		)
	}
	return fmt.Sprintf("binding error: %s", be.message)
}

// ValidationErrors returns the errors from the validate process.
func (be BindError) ValidationErrors() validator.ValidationErrors {
	switch t := be.validationErr.(type) {
	case validator.ValidationErrors:
		return t
	}
	return nil
}

// An extractorFunc extracts data from a gin context according to
// parameters specified in a field tag.
type extractor func(*gin.Context, string) (string, []string, error)

// extractQuery is an extractor tgat operated on the query
// parameters of a request.
func extractQuery(c *gin.Context, tag string) (string, []string, error) {
	name, required, defaultVal, err := parseTagKey(tag)
	if err != nil {
		return "", nil, err
	}

	rawQ := c.Request.URL.Query()[name]

	// delete empty elements so default+required will play nice together
	// append to a new collection to preserve order without too much copying
	q := make([]string, 0, len(rawQ))
	for i := range rawQ {
		if rawQ[i] != "" {
			q = append(q, rawQ[i])
		}
	}

	// XXX: deprecated, use of "default" tag is preferred
	if len(q) == 0 && defaultVal != "" {
		return name, []string{defaultVal}, nil
	}
	// XXX: deprecated, use of "validate" tag is preferred
	if len(q) == 0 && required {
		return "", nil, fmt.Errorf("missing query parameter: %s", name)
	}
	return name, q, nil
}

// extractPath is an extractor that operates on the path
// parameters of a request.
func extractPath(c *gin.Context, tag string) (string, []string, error) {
	name, required, defaultVal, err := parseTagKey(tag)
	if err != nil {
		return "", nil, err
	}
	p := c.Param(name)

	// XXX: deprecated, use of "default" tag is preferred
	if p == "" && defaultVal != "" {
		return name, []string{defaultVal}, nil
	}
	// XXX: deprecated, use of "validate" tag is preferred
	if p == "" && required {
		return "", nil, fmt.Errorf("missing path parameter: %s", name)
	}

	return name, []string{p}, nil
}

// extractHeader is an extractor that operates on the headers
// of a request.
func extractHeader(c *gin.Context, tag string) (string, []string, error) {
	name, required, defaultVal, err := parseTagKey(tag)
	if err != nil {
		return "", nil, err
	}
	header := c.GetHeader(name)

	// XXX: deprecated, use of "default" tag is preferred
	if header == "" && defaultVal != "" {
		return name, []string{defaultVal}, nil
	}
	// XXX: deprecated, use of "validate" tag is preferred
	if required && header == "" {
		return "", nil, fmt.Errorf("missing header parameter: %s", name)
	}
	return name, []string{header}, nil
}

// Public signature does not expose "required" and "default" because
// they are deprecated in favor of the "validate" and "default" tags
func parseTagKey(tag string) (string, bool, string, error) {
	parts := strings.Split(tag, ",")
	if len(parts) == 0 {
		return "", false, "", fmt.Errorf("empty tag")
	}
	name, options := parts[0], parts[1:]

	var defaultVal string

	// XXX: deprecated, required + default are kept here for backwards compatibility
	// use of "default" and "validate" tags is preferred
	// Iterate through the tag options to
	// find the required key.
	var required bool
	for _, o := range options {
		o = strings.TrimSpace(o)
		if o == RequiredTag {
			required = true
		} else if strings.HasPrefix(o, fmt.Sprintf("%s=", DefaultTag)) {
			defaultVal = strings.TrimPrefix(o, fmt.Sprintf("%s=", DefaultTag))
		} else {
			return "", false, "", fmt.Errorf("malformed tag for param '%s': unknown option '%s'", name, o)
		}
	}
	return name, required, defaultVal, nil
}

// ParseTagKey parses the given struct tag key and return the
// name of the field
func ParseTagKey(tag string) (string, error) {
	s, _, _, err := parseTagKey(tag)
	return s, err
}

// bindStringValue converts and bind the value s
// to the the reflected value v.
func bindStringValue(s string, v reflect.Value) error {
	// Ensure that the reflected value is addressable
	// and wasn't obtained by the use of an unexported
	// struct field, or calling a setter will panic.
	if !v.CanSet() {
		return fmt.Errorf("unaddressable value: %v", v)
	}
	i := reflect.New(v.Type()).Interface()

	// If the value implements the encoding.TextUnmarshaler
	// interface, bind the returned string representation.
	if unmarshaler, ok := i.(encoding.TextUnmarshaler); ok {
		if err := unmarshaler.UnmarshalText([]byte(s)); err != nil {
			return err
		}
		v.Set(reflect.Indirect(reflect.ValueOf(unmarshaler)))
		return nil
	}
	// Handle time.Duration.
	if _, ok := i.(time.Duration); ok {
		d, err := time.ParseDuration(s)
		if err != nil {
			return err
		}
		v.Set(reflect.ValueOf(d))
	}
	// Switch over the kind of the reflected value
	// and convert the string to the proper type.
	switch v.Kind() {
	case reflect.String:
		v.SetString(s)
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		i, err := strconv.ParseInt(s, 10, v.Type().Bits())
		if err != nil {
			return err
		}
		v.SetInt(i)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		i, err := strconv.ParseUint(s, 10, v.Type().Bits())
		if err != nil {
			return err
		}
		v.SetUint(i)
	case reflect.Bool:
		b, err := strconv.ParseBool(s)
		if err != nil {
			return err
		}
		v.SetBool(b)
	case reflect.Float32, reflect.Float64:
		i, err := strconv.ParseFloat(s, v.Type().Bits())
		if err != nil {
			return err
		}
		v.SetFloat(i)
	default:
		return fmt.Errorf("unsupported parameter type: %v", v.Kind())
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"
	"time"

	"github.com/banzaicloud/bank-vaults/auth"
	"github.com/banzaicloud/bank-vaults/database"
	"github.com/banzaicloud/bank-vaults/vault"
	"github.com/gin-gonic/gin"
)

func vaultExample() {
	client, err := vault.NewClient("default")
	if err != nil {
		log.Fatal(err)
	}

	log.Println("Created Vault client.")

	secret, err := client.Vault().Logical().List("secret/accesstokens")
	if err != nil {
		log.Fatal(err)
	}
	if secret != nil {
		for _, v := range secret.Data {
			log.Printf("-> %+v", v)
			for _, v := range v.([]interface{}) {
				log.Printf("-> %+v", v)
			}
		}

	} else {
		log.Println("Found nothing")
		time.Sleep(time.Minute)
		client.Close()
		time.Sleep(time.Hour)
	}
}

func gormExample() {
	secretSource, err := database.DynamicSecretDataSource("mysql", "my-role@tcp(127.0.0.1:3306)/sparky?charset=utf8&parseTime=True&loc=Local")
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("use this with GORM:\ndb, err := gorm.Open(\"mysql\", \"%s\")", secretSource)
}

func authExample() {
	engine := gin.New()
	engine.Use(auth.JWTAuth(auth.NewVaultTokenStore(""), "mys3cr3t", nil))
	engine.Use(gin.Logger(), gin.ErrorLogger())
	engine.GET("/", func(c *gin.Context) {
		user := c.Request.Context().Value(auth.CurrentUser)
		c.JSON(200, gin.H{"claims": user})
	})
	engine.Run(":9091")
}

func main() {
	os.Setenv("VAULT_ADDR", "http://localhost:8200")
	// vaultExample()
	// gormExample()
	authExample()
}
<commit_msg>Add more details to the auth example<commit_after>package main

import (
	"encoding/base32"
	"fmt"
	"log"
	"os"
	"time"

	"github.com/banzaicloud/bank-vaults/auth"
	"github.com/banzaicloud/bank-vaults/database"
	"github.com/banzaicloud/bank-vaults/vault"
	jwt "github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
)

func vaultExample() {
	client, err := vault.NewClient("default")
	if err != nil {
		log.Fatal(err)
	}

	log.Println("Created Vault client.")

	secret, err := client.Vault().Logical().List("secret/accesstokens")
	if err != nil {
		log.Fatal(err)
	}
	if secret != nil {
		for _, v := range secret.Data {
			log.Printf("-> %+v", v)
			for _, v := range v.([]interface{}) {
				log.Printf("-> %+v", v)
			}
		}

	} else {
		log.Println("Found nothing")
		time.Sleep(time.Minute)
		client.Close()
		time.Sleep(time.Hour)
	}
}

func gormExample() {
	secretSource, err := database.DynamicSecretDataSource("mysql", "my-role@tcp(127.0.0.1:3306)/sparky?charset=utf8&parseTime=True&loc=Local")
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("use this with GORM:\ndb, err := gorm.Open(\"mysql\", \"%s\")", secretSource)
}

func authExample() {
	userID := "1"
	tokenID := "123"
	signingKey := "mys3cr3t"
	signingKeyBase32 := base32.StdEncoding.EncodeToString([]byte(signingKey))

	// Issue a JWT token for the end user
	claims := &auth.ScopedClaims{
		StandardClaims: jwt.StandardClaims{
			IssuedAt:  jwt.TimeFunc().Unix(),
			ExpiresAt: 0,
			Subject:   userID,
			Id:        tokenID,
		},
	}

	jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	signedToken, err := jwtToken.SignedString([]byte(signingKeyBase32))
	if err != nil {
		panic(err)
	}

	// Use this curl command
	fmt.Printf("curl -H \"Authorization: Bearer %s\" -v http://localhost:9091/\n\n", signedToken)

	// Create a Vault Token store and insert the mirroring token
	tokenStore := auth.NewVaultTokenStore("")
	err = tokenStore.Store(userID, auth.NewToken(tokenID, "my test token"))
	if err != nil {
		panic(err)
	}

	// In the protected application you only need this part:
	// Start a Gin engine, serving and API protected via the JWT Middleware
	engine := gin.New()
	engine.Use(auth.JWTAuth(tokenStore, signingKey, nil))
	engine.Use(gin.Logger(), gin.ErrorLogger())
	engine.GET("/", func(c *gin.Context) {
		user := c.Request.Context().Value(auth.CurrentUser)
		c.JSON(200, gin.H{"claims": user})
	})
	engine.Run(":9091")
}

// REQUIRED to start a Vault 0.9 dev server with:
// vault server -dev &
func main() {
	os.Setenv("VAULT_ADDR", "http://localhost:8200")
	// vaultExample()
	// gormExample()
	authExample()
}
<|endoftext|>


<commit_before>package main

import (
	// General
	"github.com/golang/glog"
	"flag"
	"github.com/iambc/xerrors"
	"reflect"
	"os"
	"strconv"
	_ "github.com/gorilla/mux"
	"net/http"

	//DB
	"database/sql"
	_ "github.com/lib/pq"
)

var dbh *sql.DB
var dbConnString string

func main() {
    flag.Parse()
    var err error
    dbh, err = sql.Open("postgres", dbConnString)
    if err != nil {
	glog.Fatal("Connection to the database has failed")
    }
    dbConnString = os.Getenv("ABC_DB_CONN_STRING")

    go http.ListenAndServe(":"+os.Getenv("ABC_FILES_SERVER_URL"), http.FileServer(http.Dir(os.Getenv("ABC_FILES_DIR"))))
    http.HandleFunc("/api", Handler)
    http.ListenAndServe(`:`+ os.Getenv("ABC_SERVER_ENDPOINT_URL"), nil)
}

func Handler(res http.ResponseWriter, req *http.Request){
    values := req.URL.Query()
    command, isPassed := values[`command`]
    if !isPassed {
	res.Write([]byte(`{"Status":"error","Msg":"Paremeter 'command' is undefined.","Payload":null}`))
	return
    }

    var resp []byte
    var err error
    if(command[0] == `getBoards` ) {
	apiKey, isPassed := values[`api_key`]
	if !isPassed {
	    res.Write([]byte(`{"Status":"error","Msg":"Paremeter 'api_key' is undefined.","Payload":null}`))
	    return
	}
	resp, err = getBoards(apiKey[0])

    } else if(command[0] == `getActiveThreadsForBoard`) {
	apiKey, isPassed := values[`api_key`]
	if !isPassed {
	    res.Write([]byte(`{"Status":"error","Msg":"Paremeter 'api_key' is undefined.","Payload":null}`))
	    return
	}
	boardId, isPassed := values[`board_id`]
	if !isPassed {
	    res.Write([]byte(`{"Status":"error","Msg":"Paremeter 'board_id' is undefined.","Payload":null}`))
	    return
	}
	boardIdInt, err := strconv.Atoi(boardId[0])
	if err != nil {
	    res.Write([]byte(`{"Status":"error","Msg":"Wrong value for parameter board_id","Payload":null}`))
	    return
	}
	resp, err = getActiveThreadsForBoard(apiKey[0], boardIdInt)

    } else if(command[0] == `getPostsForThread`) {
	apiKey, isPassed := values[`api_key`]
	if !isPassed {
	    res.Write([]byte(`{"Status":"error","Msg":"Paremeter 'api_key' is undefined.","Payload":null}`))
	    return
	}
	threadId, isPassed := values[`thread_id`]
	if !isPassed {
	    res.Write([]byte(`{"Status":"error","Msg":"Paremeter 'board_id' is undefined.","Payload":null}`))
	    return
	}
	threadIdInt, err := strconv.Atoi(threadId[0])
	if err != nil {
	    res.Write([]byte(`{"Status":"error","Msg":"Wrong value for parameter board_id","Payload":null}`))
	    return
	}
	resp, err = getPostsForThread(apiKey[0], threadIdInt)

    } else if(command[0] == `addPostToThread`) {
	threadId, isPassed := values[`thread_id`]
	if !isPassed {
	    res.Write([]byte(`{"Status":"error","Msg":"Paremeter 'board_id' is undefined.","Payload":null}`))
	    return
	}
	threadIdInt, err := strconv.Atoi(threadId[0])
	if err != nil {
	    res.Write([]byte(`{"Status":"error","Msg":"Wrong value for parameter board_id","Payload":null}`))
	    return
	}
	threadBodyPost, isPassed := values[`thread_body_post`]
	if !isPassed {
	    res.Write([]byte(`{"Status":"error","Msg":"Paremeter 'thread_body_post' is undefined.","Payload":null}`))
	    return
	}
	attachmentUrl, isPassed := values[`attachment_id`]
	if !isPassed {
	    res.Write([]byte(`{"Status":"error","Msg":"Paremeter 'attachment_id' is undefined.","Payload":null}`))
	    return
	}
	clientRemoteAddr, isPassed := values[`clientRemoteAddr`]
	if !isPassed {
	    res.Write([]byte(`{"Status":"error","Msg":"Paremeter 'clientRemoteAddr' is undefined.","Payload":null}`))
	    return
	}
	resp, err = addPostToThread(threadIdInt, threadBodyPost[0], &attachmentUrl[0], clientRemoteAddr[0])

    } else if(command[0] == `addThread`) {
	boardId, isPassed := values[`board_id`]
	if !isPassed {
	    res.Write([]byte(`{"Status":"error","Msg":"Paremeter 'board_id' is undefined.","Payload":null}`))
	    return
	}
	boardIdInt, err := strconv.Atoi(boardId[0])
	if err != nil {
	    res.Write([]byte(`{"Status":"error","Msg":"Wrong value for parameter board_id","Payload":null}`))
	    return
	}
	threadName, isPassed := values[`thread_name`]
	if !isPassed {
	    res.Write([]byte(`{"Status":"error","Msg":"Paremeter 'thread_name' is undefined.","Payload":null}`))
	    return
	}
	resp, err = addThread(boardIdInt, threadName[0])

    } else {
	res.Write([]byte(`{"Status":"error","Msg":"No such command exists.","Payload":null}`))
	glog.Error("command: ", command[0])
    }

    res.Header().Set("Access-Control-Allow-Origin", "*")
    if err != nil{
	if string(reflect.TypeOf(err).Name())  == `XError` {
	    res.Write([]byte(`{"Status":"`+ err.(xerrors.XError).Code +`","Msg":"` + err.Error()  +`","Payload":null}`))
	} else {
	    res.Write([]byte(`{"Status":"000","Msg":"Application Error!","Payload":null}`))
	}
	glog.Error(err)
	    return
    }
    res.Write(resp)

}

<commit_msg>fix: dbconnstring initialization<commit_after>package main

/*
This file initializes the
*/

import (
	// General
	"github.com/golang/glog"
	"flag"
	"github.com/iambc/xerrors"
	"reflect"
	"os"
	"strconv"
	_ "github.com/gorilla/mux"
	"net/http"

	//DB
	"database/sql"
	_ "github.com/lib/pq"
)

var dbh *sql.DB
var dbConnString string

func main() {
    flag.Parse()
    var err error
    dbConnString = os.Getenv("ABC_DB_CONN_STRING")
    dbh, err = sql.Open("postgres", dbConnString)
    if err != nil {
	glog.Fatal("Connection to the database has failed")
    }
    dbConnString = os.Getenv("ABC_DB_CONN_STRING")

    go http.ListenAndServe(":"+os.Getenv("ABC_FILES_SERVER_URL"), http.FileServer(http.Dir(os.Getenv("ABC_FILES_DIR"))))
    http.HandleFunc("/api", QueryStringHandler)
    http.ListenAndServe(`:`+ os.Getenv("ABC_SERVER_ENDPOINT_URL"), nil)
}

func QueryStringHandler(res http.ResponseWriter, req *http.Request){
    values := req.URL.Query()
    command, isPassed := values[`command`]
    if !isPassed {
	res.Write([]byte(`{"Status":"error","Msg":"Paremeter 'command' is undefined.","Payload":null}`))
	return
    }

    var resp []byte
    var err error
    if(command[0] == `getBoards` ) {
	apiKey, isPassed := values[`api_key`]
	if !isPassed {
	    res.Write([]byte(`{"Status":"error","Msg":"Paremeter 'api_key' is undefined.","Payload":null}`))
	    return
	}
	resp, err = getBoards(apiKey[0])

    } else if(command[0] == `getActiveThreadsForBoard`) {
	apiKey, isPassed := values[`api_key`]
	if !isPassed {
	    res.Write([]byte(`{"Status":"error","Msg":"Paremeter 'api_key' is undefined.","Payload":null}`))
	    return
	}
	boardId, isPassed := values[`board_id`]
	if !isPassed {
	    res.Write([]byte(`{"Status":"error","Msg":"Paremeter 'board_id' is undefined.","Payload":null}`))
	    return
	}
	boardIdInt, err := strconv.Atoi(boardId[0])
	if err != nil {
	    res.Write([]byte(`{"Status":"error","Msg":"Wrong value for parameter board_id","Payload":null}`))
	    return
	}
	resp, err = getActiveThreadsForBoard(apiKey[0], boardIdInt)

    } else if(command[0] == `getPostsForThread`) {
	apiKey, isPassed := values[`api_key`]
	if !isPassed {
	    res.Write([]byte(`{"Status":"error","Msg":"Paremeter 'api_key' is undefined.","Payload":null}`))
	    return
	}
	threadId, isPassed := values[`thread_id`]
	if !isPassed {
	    res.Write([]byte(`{"Status":"error","Msg":"Paremeter 'board_id' is undefined.","Payload":null}`))
	    return
	}
	threadIdInt, err := strconv.Atoi(threadId[0])
	if err != nil {
	    res.Write([]byte(`{"Status":"error","Msg":"Wrong value for parameter board_id","Payload":null}`))
	    return
	}
	resp, err = getPostsForThread(apiKey[0], threadIdInt)

    } else if(command[0] == `addPostToThread`) {
	threadId, isPassed := values[`thread_id`]
	if !isPassed {
	    res.Write([]byte(`{"Status":"error","Msg":"Paremeter 'board_id' is undefined.","Payload":null}`))
	    return
	}
	threadIdInt, err := strconv.Atoi(threadId[0])
	if err != nil {
	    res.Write([]byte(`{"Status":"error","Msg":"Wrong value for parameter board_id","Payload":null}`))
	    return
	}
	threadBodyPost, isPassed := values[`thread_body_post`]
	if !isPassed {
	    res.Write([]byte(`{"Status":"error","Msg":"Paremeter 'thread_body_post' is undefined.","Payload":null}`))
	    return
	}
	attachmentUrl, isPassed := values[`attachment_id`]
	if !isPassed {
	    res.Write([]byte(`{"Status":"error","Msg":"Paremeter 'attachment_id' is undefined.","Payload":null}`))
	    return
	}
	clientRemoteAddr, isPassed := values[`clientRemoteAddr`]
	if !isPassed {
	    res.Write([]byte(`{"Status":"error","Msg":"Paremeter 'clientRemoteAddr' is undefined.","Payload":null}`))
	    return
	}
	resp, err = addPostToThread(threadIdInt, threadBodyPost[0], &attachmentUrl[0], clientRemoteAddr[0])

    } else if(command[0] == `addThread`) {
	boardId, isPassed := values[`board_id`]
	if !isPassed {
	    res.Write([]byte(`{"Status":"error","Msg":"Paremeter 'board_id' is undefined.","Payload":null}`))
	    return
	}
	boardIdInt, err := strconv.Atoi(boardId[0])
	if err != nil {
	    res.Write([]byte(`{"Status":"error","Msg":"Wrong value for parameter board_id","Payload":null}`))
	    return
	}
	threadName, isPassed := values[`thread_name`]
	if !isPassed {
	    res.Write([]byte(`{"Status":"error","Msg":"Paremeter 'thread_name' is undefined.","Payload":null}`))
	    return
	}
	resp, err = addThread(boardIdInt, threadName[0])

    } else {
	res.Write([]byte(`{"Status":"error","Msg":"No such command exists.","Payload":null}`))
	glog.Error("command: ", command[0])
    }

    res.Header().Set("Access-Control-Allow-Origin", "*")
    if err != nil{
	if string(reflect.TypeOf(err).Name())  == `XError` {
	    res.Write([]byte(`{"Status":"`+ err.(xerrors.XError).Code +`","Msg":"` + err.Error()  +`","Payload":null}`))
	} else {
	    res.Write([]byte(`{"Status":"000","Msg":"Application Error!","Payload":null}`))
	}
	glog.Error(err)
	    return
    }
    res.Write(resp)

}

<|endoftext|>


<commit_before>/*
Package vlq implements a library for handling variable-length quantity (vlq)
values specified by the MIDI file format.

See: https://www.midi.org/images/downloads/complete_midi_96-1-3.pdf Standard MIDI Files 1.0
*/
package vlq

import (
	"bufio"
	"io"
	"errors"
	"fmt"
)

// The maximum allowed VLQ value as defined by the spec
const MAX = 0x0FFFFFFF

// Read reads a single VLQ value from a bytes.Reader
func ReadVLQ(r io.Reader) (n int, read int, err error) {

	buffer := bufio.NewReader(r)
	mada := true
	for mada {
		// read the next byte
		b, err := buffer.ReadByte()
		if err != nil {
			return 0, read, err
		}

		// increment read bytes counter
		read++

		// add the 7 LSBs to the result
		n ^= int(b & 0x7f)

		// if the MSB is 1, prepare for the next iteration
		if mada = 1 == b>>7; mada {
			n <<= 7
		}

		// check for exceeding max value defined in spec
		if n > MAX {
			return 0, read, errors.New(fmt.Sprintf("exceeded maximum vlq value [%d]", MAX))
		}
	}

	return
}
<commit_msg>VLQ Reader cleanup<commit_after>/*
Package vlq implements a library for handling variable-length quantity (vlq)
values specified by the MIDI file format.

See: https://www.midi.org/images/downloads/complete_midi_96-1-3.pdf Standard MIDI Files 1.0
*/
package vlq

import (
	"bufio"
	"errors"
	"fmt"
	"io"
)

// The maximum allowed VLQ value as defined by the spec
const MAX = 0x0FFFFFFF

// Read reads a single VLQ value from a bytes.Reader
func ReadVLQ(r io.Reader) (n int, read int, err error) {

	buffer := bufio.NewReader(r)
	mada := true
	for mada {
		// read the next byte
		b, err := buffer.ReadByte()
		if err != nil {
			return 0, read, err
		}

		// increment read bytes counter
		read++

		// add the 7 LSBs to the result
		n ^= int(b & 0x7f)

		// if the MSB is 1, prepare for the next iteration
		if mada = 1 == b>>7; mada {
			n <<= 7
		}

		// check for exceeding max value defined in spec
		if n > MAX {
			return 0, read, errors.New(fmt.Sprintf("exceeded maximum vlq value [%d]", MAX))
		}
	}

	return
}
<|endoftext|>


<commit_before>package secret

import (
	"strings"

	"github.com/rancher/types/apis/core/v1"
	"github.com/rancher/types/apis/management.cattle.io/v3"
	"github.com/rancher/types/config"
	"github.com/sirupsen/logrus"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
)

// SecretController listens for secret CUD in management API
// and propagates the changes to all corresponding namespaces in cluster API

// NamespaceController listens to cluster namespace events,
// reads secrets from the management namespace of corresponding project,
// and creates the secrets in the cluster namespace

const (
	projectIDLabel             = "field.cattle.io/projectId"
	create                     = "create"
	update                     = "update"
	projectNamespaceAnnotation = "management.cattle.io/system-namespace"
	userSecretAnnotation       = "secret.user.cattle.io/secret"
)

type Controller struct {
	secrets                   v1.SecretInterface
	clusterNamespaceLister    v1.NamespaceLister
	managementNamespaceLister v1.NamespaceLister
	projectLister             v3.ProjectLister
	clusterName               string
}

func Register(cluster *config.UserContext) {
	clusterSecretsClient := cluster.Core.Secrets("")
	s := &Controller{
		secrets:                   clusterSecretsClient,
		clusterNamespaceLister:    cluster.Core.Namespaces("").Controller().Lister(),
		managementNamespaceLister: cluster.Management.Core.Namespaces("").Controller().Lister(),
		projectLister:             cluster.Management.Management.Projects("").Controller().Lister(),
		clusterName:               cluster.ClusterName,
	}

	n := &NamespaceController{
		clusterSecretsClient: clusterSecretsClient,
		managementSecrets:    cluster.Management.Core.Secrets("").Controller().Lister(),
	}
	cluster.Core.Namespaces("").AddHandler("secretsController", n.sync)
	cluster.Management.Core.Secrets("").AddClusterScopedLifecycle("secretsController", cluster.ClusterName, s)
}

type NamespaceController struct {
	clusterSecretsClient v1.SecretInterface
	managementSecrets    v1.SecretLister
}

func (n *NamespaceController) sync(key string, obj *corev1.Namespace) error {
	if obj == nil || obj.DeletionTimestamp != nil {
		return nil
	}
	// field.cattle.io/projectId value is <cluster name>:<project name>
	if obj.Annotations[projectIDLabel] != "" {
		parts := strings.Split(obj.Annotations[projectIDLabel], ":")
		if len(parts) == 2 {
			// on the management side, secret's namespace name equals to project name
			secrets, err := n.managementSecrets.List(parts[1], labels.NewSelector())
			if err != nil {
				return err
			}
			for _, secret := range secrets {
				namespacedSecret := getNamespacedSecret(secret, obj.Name)
				_, err := n.clusterSecretsClient.Create(namespacedSecret)
				if err != nil && !errors.IsAlreadyExists(err) {
					return err
				}
			}
		}
	}
	return nil
}

func (s *Controller) Create(obj *corev1.Secret) (*corev1.Secret, error) {
	return nil, s.createOrUpdate(obj, create)
}

func (s *Controller) Updated(obj *corev1.Secret) (*corev1.Secret, error) {
	return nil, s.createOrUpdate(obj, update)
}

func (s *Controller) Remove(obj *corev1.Secret) (*corev1.Secret, error) {
	clusterNamespaces, err := s.getClusterNamespaces(obj)
	if err != nil {
		return nil, err
	}

	for _, namespace := range clusterNamespaces {
		logrus.Infof("Deleting secret [%s] in namespace [%s]", obj.Name, namespace.Name)
		if err := s.secrets.DeleteNamespaced(namespace.Name, obj.Name, &metav1.DeleteOptions{}); err != nil && !errors.IsNotFound(err) {
			return nil, err
		}
	}
	return nil, nil
}

func (s *Controller) getClusterNamespaces(obj *corev1.Secret) ([]*corev1.Namespace, error) {
	var toReturn []*corev1.Namespace
	projectNamespace, err := s.managementNamespaceLister.Get("", obj.Namespace)
	if err != nil {
		if errors.IsNotFound(err) {
			logrus.Warnf("Project namespace [%s] can't be found", obj.Namespace)
			return toReturn, nil
		}
		return toReturn, err
	}
	if projectNamespace.Annotations == nil {
		return toReturn, nil
	}
	if val, ok := projectNamespace.Annotations[projectNamespaceAnnotation]; !(ok && val == "true") {
		return toReturn, nil
	}

	// Ignore projects from other clusters. Project namespace name = project name, so use it to locate the project
	_, err = s.projectLister.Get(s.clusterName, projectNamespace.Name)
	if err != nil {
		if errors.IsNotFound(err) {
			logrus.Warnf("Project [%s] can't be found", projectNamespace.Name)
			return toReturn, nil
		}
		return toReturn, err
	}

	namespaces, err := s.clusterNamespaceLister.List("", labels.NewSelector())
	if err != nil {
		return toReturn, err
	}
	// system project namespace name == project.Name
	projectID := obj.Namespace

	for _, namespace := range namespaces {
		parts := strings.Split(namespace.Annotations[projectIDLabel], ":")
		if len(parts) == 2 && parts[1] == projectID {
			toReturn = append(toReturn, namespace)
		}
	}
	return toReturn, nil
}

func (s *Controller) createOrUpdate(obj *corev1.Secret, action string) error {
	clusterNamespaces, err := s.getClusterNamespaces(obj)
	if err != nil {
		return err
	}
	for _, namespace := range clusterNamespaces {
		// copy the secret into namespace
		namespacedSecret := getNamespacedSecret(obj, namespace.Name)
		switch action {
		case create:
			logrus.Infof("Copying secret [%s] into namespace [%s]", namespacedSecret.Name, namespace.Name)
			_, err := s.secrets.Create(namespacedSecret)
			if err != nil && !errors.IsAlreadyExists(err) {
				return err
			}
		case update:
			_, err := s.secrets.Update(namespacedSecret)
			if err != nil && !errors.IsNotFound(err) {
				return err
			} else if errors.IsNotFound(err) {
				_, err := s.secrets.Create(namespacedSecret)
				if err != nil {
					return err
				}
			}
		}
	}

	return nil
}

func getNamespacedSecret(obj *corev1.Secret, namespace string) *corev1.Secret {
	namespacedSecret := &corev1.Secret{}
	namespacedSecret.Name = obj.Name
	namespacedSecret.Kind = obj.Kind
	namespacedSecret.Data = obj.Data
	namespacedSecret.StringData = obj.StringData
	namespacedSecret.Namespace = namespace
	namespacedSecret.Type = obj.Type
	namespacedSecret.Annotations = make(map[string]string)
	copyMap(obj.Annotations, namespacedSecret.Annotations)
	namespacedSecret.Annotations[userSecretAnnotation] = "true"
	return namespacedSecret
}

func copyMap(src map[string]string, dst map[string]string) {
	for k, v := range src {
		dst[k] = v
	}
}
<commit_msg>ClusterScopedLifecycle to Lifecycle for secret<commit_after>package secret

import (
	"strings"

	"github.com/rancher/types/apis/core/v1"
	"github.com/rancher/types/apis/management.cattle.io/v3"
	"github.com/rancher/types/config"
	"github.com/sirupsen/logrus"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
)

// SecretController listens for secret CUD in management API
// and propagates the changes to all corresponding namespaces in cluster API

// NamespaceController listens to cluster namespace events,
// reads secrets from the management namespace of corresponding project,
// and creates the secrets in the cluster namespace

const (
	projectIDLabel             = "field.cattle.io/projectId"
	create                     = "create"
	update                     = "update"
	projectNamespaceAnnotation = "management.cattle.io/system-namespace"
	userSecretAnnotation       = "secret.user.cattle.io/secret"
)

type Controller struct {
	secrets                   v1.SecretInterface
	clusterNamespaceLister    v1.NamespaceLister
	managementNamespaceLister v1.NamespaceLister
	projectLister             v3.ProjectLister
	clusterName               string
}

func Register(cluster *config.UserContext) {
	clusterSecretsClient := cluster.Core.Secrets("")
	s := &Controller{
		secrets:                   clusterSecretsClient,
		clusterNamespaceLister:    cluster.Core.Namespaces("").Controller().Lister(),
		managementNamespaceLister: cluster.Management.Core.Namespaces("").Controller().Lister(),
		projectLister:             cluster.Management.Management.Projects("").Controller().Lister(),
		clusterName:               cluster.ClusterName,
	}

	n := &NamespaceController{
		clusterSecretsClient: clusterSecretsClient,
		managementSecrets:    cluster.Management.Core.Secrets("").Controller().Lister(),
	}
	cluster.Core.Namespaces("").AddHandler("secretsController", n.sync)
	cluster.Management.Core.Secrets("").AddLifecycle("secretsController", s)
}

type NamespaceController struct {
	clusterSecretsClient v1.SecretInterface
	managementSecrets    v1.SecretLister
}

func (n *NamespaceController) sync(key string, obj *corev1.Namespace) error {
	if obj == nil || obj.DeletionTimestamp != nil {
		return nil
	}
	// field.cattle.io/projectId value is <cluster name>:<project name>
	if obj.Annotations[projectIDLabel] != "" {
		parts := strings.Split(obj.Annotations[projectIDLabel], ":")
		if len(parts) == 2 {
			// on the management side, secret's namespace name equals to project name
			secrets, err := n.managementSecrets.List(parts[1], labels.NewSelector())
			if err != nil {
				return err
			}
			for _, secret := range secrets {
				namespacedSecret := getNamespacedSecret(secret, obj.Name)
				_, err := n.clusterSecretsClient.Create(namespacedSecret)
				if err != nil && !errors.IsAlreadyExists(err) {
					return err
				}
			}
		}
	}
	return nil
}

func (s *Controller) Create(obj *corev1.Secret) (*corev1.Secret, error) {
	return nil, s.createOrUpdate(obj, create)
}

func (s *Controller) Updated(obj *corev1.Secret) (*corev1.Secret, error) {
	return nil, s.createOrUpdate(obj, update)
}

func (s *Controller) Remove(obj *corev1.Secret) (*corev1.Secret, error) {
	clusterNamespaces, err := s.getClusterNamespaces(obj)
	if err != nil {
		return nil, err
	}

	for _, namespace := range clusterNamespaces {
		logrus.Infof("Deleting secret [%s] in namespace [%s]", obj.Name, namespace.Name)
		if err := s.secrets.DeleteNamespaced(namespace.Name, obj.Name, &metav1.DeleteOptions{}); err != nil && !errors.IsNotFound(err) {
			return nil, err
		}
	}
	return nil, nil
}

func (s *Controller) getClusterNamespaces(obj *corev1.Secret) ([]*corev1.Namespace, error) {
	var toReturn []*corev1.Namespace
	projectNamespace, err := s.managementNamespaceLister.Get("", obj.Namespace)
	if err != nil {
		if errors.IsNotFound(err) {
			logrus.Warnf("Project namespace [%s] can't be found", obj.Namespace)
			return toReturn, nil
		}
		return toReturn, err
	}
	if projectNamespace.Annotations == nil {
		return toReturn, nil
	}
	if val, ok := projectNamespace.Annotations[projectNamespaceAnnotation]; !(ok && val == "true") {
		return toReturn, nil
	}

	// Ignore projects from other clusters. Project namespace name = project name, so use it to locate the project
	_, err = s.projectLister.Get(s.clusterName, projectNamespace.Name)
	if err != nil {
		if errors.IsNotFound(err) {
			logrus.Warnf("Project [%s] can't be found", projectNamespace.Name)
			return toReturn, nil
		}
		return toReturn, err
	}

	namespaces, err := s.clusterNamespaceLister.List("", labels.NewSelector())
	if err != nil {
		return toReturn, err
	}
	// system project namespace name == project.Name
	projectID := obj.Namespace

	for _, namespace := range namespaces {
		parts := strings.Split(namespace.Annotations[projectIDLabel], ":")
		if len(parts) == 2 && parts[1] == projectID {
			toReturn = append(toReturn, namespace)
		}
	}
	return toReturn, nil
}

func (s *Controller) createOrUpdate(obj *corev1.Secret, action string) error {
	if obj.Annotations[projectIDLabel] != "" {
		parts := strings.Split(obj.Annotations[projectIDLabel], ":")
		if len(parts) == 2 {
			if parts[0] != s.clusterName {
				return nil
			}
		}
	}
	clusterNamespaces, err := s.getClusterNamespaces(obj)
	if err != nil {
		return err
	}
	for _, namespace := range clusterNamespaces {
		// copy the secret into namespace
		namespacedSecret := getNamespacedSecret(obj, namespace.Name)
		switch action {
		case create:
			logrus.Infof("Copying secret [%s] into namespace [%s]", namespacedSecret.Name, namespace.Name)
			_, err := s.secrets.Create(namespacedSecret)
			if err != nil && !errors.IsAlreadyExists(err) {
				return err
			}
		case update:
			_, err := s.secrets.Update(namespacedSecret)
			if err != nil && !errors.IsNotFound(err) {
				return err
			} else if errors.IsNotFound(err) {
				_, err := s.secrets.Create(namespacedSecret)
				if err != nil {
					return err
				}
			}
		}
	}

	return nil
}

func getNamespacedSecret(obj *corev1.Secret, namespace string) *corev1.Secret {
	namespacedSecret := &corev1.Secret{}
	namespacedSecret.Name = obj.Name
	namespacedSecret.Kind = obj.Kind
	namespacedSecret.Data = obj.Data
	namespacedSecret.StringData = obj.StringData
	namespacedSecret.Namespace = namespace
	namespacedSecret.Type = obj.Type
	namespacedSecret.Annotations = make(map[string]string)
	copyMap(obj.Annotations, namespacedSecret.Annotations)
	namespacedSecret.Annotations[userSecretAnnotation] = "true"
	return namespacedSecret
}

func copyMap(src map[string]string, dst map[string]string) {
	for k, v := range src {
		dst[k] = v
	}
}
<|endoftext|>


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

// +build appengine !go1.4

package siegreader

// no mmap on appengine
func mmapable(sz int64) bool {
	return false
}

func mmapFile(f *os.File) []byte {
	return nil
}
<commit_msg>trap fixing<commit_after>// Copyright 2014 Richard Lehane. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build appengine !go1.4

package siegreader

import "os"

// no mmap on appengine
func mmapable(sz int64) bool {
	return false
}

func mmapFile(f *os.File) []byte {
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"os"
	"time"
)

var (
	addr       = flag.String("http", ":8080", "HTTP address to serve on")
	tlsAddr    = flag.String("https", "", "HTTPS address to serve on")
	pemFile    = flag.String("pem-file", "", "HTTPS / SSL certificate .pem file")
	keyFile    = flag.String("key-file", "", "HTTPS / SSL certificate .key file")
	update     = flag.Bool("update", true, "update via Git and shutdown server after pull")
	updateRate = flag.String("update-rate", "60s", "rate at which to check for updates via Git")

	src = &GitUpdater{
		Dir: ".",
	}
	tmpls       = template.Must(template.ParseGlob("templates/*"))
	lastUpdate  = time.Now()
	updateRateT time.Duration
)

func handler(w http.ResponseWriter, r *http.Request) error {
	return fmt.Fprintf(w, "Hello world!")
}

func logHandler(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log.Printf("%v %v\n", r.Method, r.URL)
		h.ServeHTTP(w, r)
	})
}

func errorHandler(h func(w http.ResponseWriter, r *http.Request) error) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		err := h(w, r)
		if err == nil {
			return
		}

		// Render the error template.
		data := &TemplateData{
			Request: r,
			Error:   err.Error(),
		}
		if err := tmpls.ExecuteTemplate(w, errorTemplate, data); err != nil {
			panic(err)
		}
	})
}

func checkForUpdates() {
	// If not enough time has elapsed, skip the update.
	if time.Since(lastUpdate) < updateRateT {
		return
	}
	lastUpdate = time.Now()

	// Check for updates.
	updated, err := src.Update()
	if err != nil {
		log.Println("Update error:", err)
		return
	}
	if updated {
		log.Println("Updated source code. Exiting server..")
		os.Exit(0)
	}
	log.Println("checked for updates (none available)")
}

func init() {
	if *update {
		go func() {
			for {
				time.Sleep(updateRateT)
				checkForUpdates()
			}
		}()
	}
}

func main() {
	flag.Parse()

	// Parse update rate flag.
	var err error
	updateRateT, err = time.ParseDuration(*updateRate)
	if err != nil {
		log.Fatal(err)
	}

	// Static file hosting
	http.Handle("/static/", http.StripPrefix("/static/", logHandler(http.FileServer(http.Dir("static/")))))

	// App handler.
	http.HandleFunc("/", logHandler(errorHandler(handler)))

	// Start HTTPS server:
	if *tlsAddr != "" {
		go func() {
			if *pemFile == "" {
				log.Fatal("expected -pem-file flag")
			}
			if *keyFile == "" {
				log.Fatal("expected -key-file flag")
			}
			log.Println("Serving on", *tlsAddr)
			log.Fatal(http.ListenAndServeTLS(*tlsAddr, *pemFile, *keyFile, nil))
		}()
	}

	// Start HTTP server:
	log.Println("Serving on", *addr)
	log.Fatal(http.ListenAndServe(*addr, nil))
}
<commit_msg>cmd/fiz3d-org: implement basic templating system<commit_after>package main

import (
	"flag"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"
)

var (
	addr       = flag.String("http", ":8080", "HTTP address to serve on")
	tlsAddr    = flag.String("https", "", "HTTPS address to serve on")
	pemFile    = flag.String("pem-file", "", "HTTPS / SSL certificate .pem file")
	keyFile    = flag.String("key-file", "", "HTTPS / SSL certificate .key file")
	update     = flag.Bool("update", true, "update via Git and shutdown server after pull")
	updateRate = flag.String("update-rate", "60s", "rate at which to check for updates via Git")
	dev        = flag.Bool("dev", false, "reload all templates on each request")

	errorTemplate = "error"      // Template to use for errors.
	templateGlob  = "**/*.tmpl"  // Glob to match all template files.
	templateDir   = "templates/" // Relative directory that templates reside in.

	src = &GitUpdater{
		Dir: ".",
	}
	lastUpdate  = time.Now()
	tmpls       *template.Template
	updateRateT time.Duration
)

func reloadTemplates() error {
	matches, err := filepath.Glob(templateGlob)
	if err != nil {
		return err
	}
	tmpls = template.New("")
	for _, m := range matches {
		name := strings.TrimPrefix(m, templateDir)
		name = strings.TrimSuffix(name, filepath.Ext(name))
		if _, err := tmpls.New(name).Parse(m); err != nil {
			return err
		}
	}
	return nil
}

type TemplateData struct {
	Request *http.Request
	Error   string
}

func handler(w http.ResponseWriter, r *http.Request) error {
	if *dev {
		if err := reloadTemplates(); err != nil {
			return err
		}
	}

	var data = &TemplateData{
		Request: r,
	}

	// Determine template name.
	tmplName := r.URL.Path[1:]
	if stat, err := os.Stat(filepath.Join(templateDir, tmplName)); err != nil {
		return err
	} else {
		if stat.IsDir() {
			tmplName = "index"
		}
	}

	// Find the requested page.
	root := tmpls.Lookup(tmplName)
	if root == nil {
		// Couldn't find the page, render the error page.
		w.WriteHeader(http.StatusNotFound)
		return fmt.Errorf("%v - %v", http.StatusNotFound, http.StatusText(http.StatusNotFound))
	}

	// Execute the requested template page.
	return root.Execute(w, data)
}

func logHandler(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log.Printf("%v %v\n", r.Method, r.URL)
		h.ServeHTTP(w, r)
	})
}

func errorHandler(h func(w http.ResponseWriter, r *http.Request) error) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		err := h(w, r)
		if err == nil {
			return
		}

		// Render the error template.
		data := &TemplateData{
			Request: r,
			Error:   err.Error(),
		}
		if err := tmpls.ExecuteTemplate(w, errorTemplate, data); err != nil {
			panic(err)
		}
	})
}

func checkForUpdates() {
	// If not enough time has elapsed, skip the update.
	if time.Since(lastUpdate) < updateRateT {
		return
	}
	lastUpdate = time.Now()

	// Check for updates.
	updated, err := src.Update()
	if err != nil {
		log.Println("Update error:", err)
		return
	}
	if updated {
		log.Println("Updated source code. Exiting server..")
		os.Exit(0)
	}
	log.Println("checked for updates (none available)")
}

func init() {
	if err := reloadTemplates(); err != nil {
		log.Fatal(err)
	}

	if *update {
		go func() {
			for {
				time.Sleep(updateRateT)
				checkForUpdates()
			}
		}()
	}
}

func main() {
	flag.Parse()

	// Parse update rate flag.
	var err error
	updateRateT, err = time.ParseDuration(*updateRate)
	if err != nil {
		log.Fatal(err)
	}

	// Static file hosting
	http.Handle("/static/", logHandler(http.StripPrefix("/static/", http.FileServer(http.Dir("static/")))))

	// App handler.
	http.Handle("/", logHandler(errorHandler(handler)))

	// Start HTTPS server:
	if *tlsAddr != "" {
		go func() {
			if *pemFile == "" {
				log.Fatal("expected -pem-file flag")
			}
			if *keyFile == "" {
				log.Fatal("expected -key-file flag")
			}
			log.Println("Serving on", *tlsAddr)
			log.Fatal(http.ListenAndServeTLS(*tlsAddr, *pemFile, *keyFile, nil))
		}()
	}

	// Start HTTP server:
	log.Println("Serving on", *addr)
	log.Fatal(http.ListenAndServe(*addr, nil))
}
<|endoftext|>


<commit_before>package uplink

import (
	"fmt"
	"sync"
	"testing"

	"github.com/brocaar/loraserver/api/gw"
	"github.com/brocaar/loraserver/internal/common"
	"github.com/brocaar/loraserver/internal/models"
	"github.com/brocaar/loraserver/internal/test"
	"github.com/brocaar/lorawan"
	. "github.com/smartystreets/goconvey/convey"
)

func TestCollectAndCallOnce(t *testing.T) {
	conf := test.GetConfig()

	Convey("Given a Redis connection pool", t, func() {
		p := common.NewRedisPool(conf.RedisURL)
		test.MustFlushRedis(p)

		Convey("Given a single LoRaWAN packet", func() {
			phy := lorawan.PHYPayload{
				MHDR: lorawan.MHDR{
					MType: lorawan.UnconfirmedDataUp,
					Major: lorawan.LoRaWANR1,
				},
				MIC:        [4]byte{1, 2, 3, 4},
				MACPayload: &lorawan.MACPayload{},
			}

			testTable := []struct {
				Gateways []lorawan.EUI64
				Count    int
			}{
				{
					[]lorawan.EUI64{
						{1, 1, 1, 1, 1, 1, 1, 1},
					},
					1,
				}, {
					[]lorawan.EUI64{
						{2, 1, 1, 1, 1, 1, 1, 1},
						{2, 2, 2, 2, 2, 2, 2, 2},
					},
					2,
				}, {
					[]lorawan.EUI64{
						{3, 1, 1, 1, 1, 1, 1, 1},
						{3, 2, 2, 2, 2, 2, 2, 2},
						{3, 2, 2, 2, 2, 2, 2, 2},
					},
					2,
				},
			}

			for i, test := range testTable {
				Convey(fmt.Sprintf("When running test %d, then %d items in the RXInfoSet are expected", i, test.Count), func() {
					var received int
					var called int

					cb := func(packet models.RXPacket) error {
						called = called + 1
						received = len(packet.RXInfoSet)
						return nil
					}

					var wg sync.WaitGroup
					for _, g := range test.Gateways {
						wg.Add(1)
						packet := gw.RXPacket{
							RXInfo: gw.RXInfo{
								MAC: g,
							},
							PHYPayload: phy,
						}
						go func() {
							err := collectAndCallOnce(p, packet, cb)
							if err != nil {
								t.Error(err)
							}
							wg.Done()
						}()
					}
					wg.Wait()

					So(called, ShouldEqual, 1)
					So(received, ShouldEqual, test.Count)
				})
			}
		})

	})
}
<commit_msg>Fix deduplication test.<commit_after>package uplink

import (
	"fmt"
	"sync"
	"testing"
	"time"

	"github.com/brocaar/loraserver/api/gw"
	"github.com/brocaar/loraserver/internal/common"
	"github.com/brocaar/loraserver/internal/models"
	"github.com/brocaar/loraserver/internal/test"
	"github.com/brocaar/lorawan"
	. "github.com/smartystreets/goconvey/convey"
)

func TestCollectAndCallOnce(t *testing.T) {
	conf := test.GetConfig()
	p := common.NewRedisPool(conf.RedisURL)
	common.RedisPool = p
	common.DeduplicationDelay = time.Millisecond * 500

	Convey("Given a Redis connection pool", t, func() {
		test.MustFlushRedis(p)

		Convey("Given a single LoRaWAN packet", func() {
			testTable := []struct {
				PHYPayload lorawan.PHYPayload
				Gateways   []lorawan.EUI64
				Count      int
			}{
				{
					lorawan.PHYPayload{
						MHDR: lorawan.MHDR{
							MType: lorawan.UnconfirmedDataUp,
							Major: lorawan.LoRaWANR1,
						},
						MIC:        [4]byte{1, 2, 3, 4},
						MACPayload: &lorawan.MACPayload{},
					},
					[]lorawan.EUI64{
						{1, 1, 1, 1, 1, 1, 1, 1},
					},
					1,
				}, {
					lorawan.PHYPayload{
						MHDR: lorawan.MHDR{
							MType: lorawan.UnconfirmedDataUp,
							Major: lorawan.LoRaWANR1,
						},
						MIC:        [4]byte{2, 2, 3, 4},
						MACPayload: &lorawan.MACPayload{},
					},
					[]lorawan.EUI64{
						{2, 1, 1, 1, 1, 1, 1, 1},
						{2, 2, 2, 2, 2, 2, 2, 2},
					},
					2,
				}, {
					lorawan.PHYPayload{
						MHDR: lorawan.MHDR{
							MType: lorawan.UnconfirmedDataUp,
							Major: lorawan.LoRaWANR1,
						},
						MIC:        [4]byte{3, 2, 3, 4},
						MACPayload: &lorawan.MACPayload{},
					},
					[]lorawan.EUI64{
						{3, 1, 1, 1, 1, 1, 1, 1},
						{3, 2, 2, 2, 2, 2, 2, 2},
						{3, 2, 2, 2, 2, 2, 2, 2},
					},
					2,
				},
			}

			for i, test := range testTable {
				Convey(fmt.Sprintf("When running test %d, then %d items in the RXInfoSet are expected", i, test.Count), func() {
					var received int
					var called int

					cb := func(packet models.RXPacket) error {
						called = called + 1
						received = len(packet.RXInfoSet)
						return nil
					}

					var wg sync.WaitGroup
					for _, g := range test.Gateways {
						wg.Add(1)
						packet := gw.RXPacket{
							RXInfo: gw.RXInfo{
								MAC: g,
							},
							PHYPayload: test.PHYPayload,
						}
						go func() {
							err := collectAndCallOnce(p, packet, cb)
							if err != nil {
								t.Error(err)
							}
							wg.Done()
						}()
					}
					wg.Wait()

					So(called, ShouldEqual, 1)
					So(received, ShouldEqual, test.Count)
				})
			}
		})

	})
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2013 Leandro López

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.
*/

/*
gedis server - Generic Redis server implementation

This package allows to create servers that can talk to clients by
using the Redis protocol

Redis protocol: http://redis.io/topics/protocol

As an example, the following implements a very simple Redis server
that only responds to the PING command:

    package main

    import (
    	"fmt"
    	gedis "github.com/inkel/gedis/server"
    	"os"
    	"os/signal"
    )

    func main() {
    	c := make(chan os.Signal, 1)
    	signal.Notify(c, os.Interrupt, os.Kill)

    	s, err := gedis.NewServer("tcp", ":10003")
    	if err != nil {
    		panic(err)
    	}
    	defer s.Close()

    	pong := []byte("+PONG\r\n")
    	earg := []byte("-ERR wrong number of arguments for 'ping' command\r\n")

    	s.Handle("PING", func(c *gedis.Client, args []string) error {
    		if len(args) != 0 {
    			c.Write(earg)
    			return nil
    		} else {
    			c.Write(pong)
    		}

    		return nil
    	})

    	go s.Loop()

    	sig := <-c

    	fmt.Println("Bye!", sig)
    }
*/
package server

import (
	"fmt"
	"github.com/inkel/gedis"
	"io"
	"net"
	"strings"
)

// Interface for reading from Redis clients
type Reader interface {
	Read([]byte) (int, error)
}

// Read the length of a bulk or multi-bulk block
func readLength(r Reader) (n int64, err error) {
	b := make([]byte, 1)

	var sign int64 = 1

	_, err = r.Read(b)
	if err != nil {
		return
	}
	if b[0] == '-' {
		sign = -1
		b[0] = '0'
	}

	for {
		if b[0] >= '0' && b[0] <= '9' {
			n = n*10 + int64(b[0]-'0')
		} else if b[0] == '\r' {
			_, err = r.Read(b)
			if b[0] == '\n' {
				break
			} else {
				return 0, gedis.NewParseError("Invalid EOF")
			}
		} else {
			return 0, gedis.NewParseError("Invalid character")
		}

		_, err = r.Read(b)
		if err == io.EOF {
			break
		} else if err != nil {
			return
		}
	}

	return sign * n, nil
}

// Read a bulk as defined in the Redis protocol
func readBulk(r Reader) (bs []byte, err error) {
	var b byte

	b, err = readByte(r)
	if err != nil {
		return bs, err
	} else if b != '$' {
		return bs, gedis.NewParseError("Invalid first character")
	}

	n, err := readLength(r)
	if err != nil {
		return bs, err
	}

	bs = make([]byte, n)

	_, err = r.Read(bs)
	if err != nil {
		return bs, err
	}

	crlf := make([]byte, 2)

	if _, err = r.Read(crlf); err != nil {
		return bs, err
	}

	if crlf[0] != '\r' || crlf[1] != '\n' {
		return bs, gedis.NewParseError("Invalid EOL")
	}

	return
}

// Reads the next byte in Reader
func readByte(r Reader) (byte, error) {
	b := make([]byte, 1)
	_, err := r.Read(b)
	return b[0], err
}

// Read a multi-bulk request from a Redis client
//
// Redis client can only send multi-bulk requests to a Redis
// server. In truth they can also send an inline request, however that
// is currently not covered by this implementation
func Read(r Reader) (res [][]byte, err error) {
	var b byte

	b, err = readByte(r)
	if err != nil {
		return
	}

	if b != '*' {
		return res, gedis.NewParseError("Invalid first character")
	} else {
		n, err := readLength(r)
		if err != nil {
			return res, err
		}

		res = make([][]byte, n)

		for i := int64(0); i < n; i++ {
			res[i], err = readBulk(r)
			if err != nil {
				return res, err
			}
		}
	}

	return res, err
}

// Holds pointers to the current Server and client net.Conn
type Client struct {
	server *Server
	conn   *net.Conn
}

// Disconnects a client
func (c *Client) Close() {
	conn := *c.conn
	conn.Close()
}

// Read from the client, parsing the input with the Redis protocol
func (c *Client) Read() ([][]byte, error) {
	return Read(*c.conn)
}

// Send a sequence of bytes to a client
func (c *Client) Write(bytes []byte) (int, error) {
	conn := *c.conn
	return conn.Write(bytes)
}

// Sends an error to the client, formatted accordingly to the Redis
// protocol
func (c *Client) Error(err error) (int, error) {
	return c.Write(gedis.WriteError(err))
}

// Sends a string formatted as an error to the client
func (c *Client) Errorf(format string, args ...interface{}) (int, error) {
	return c.Error(fmt.Errorf(format, args...))
}

// Sends a status response, formatted accordingly to the Redis
// protocol
func (c *Client) Status(status string) (int, error) {
	return c.Write(gedis.WriteStatus(status))
}

// Signature that command handler functions must have
type Handler func(c *Client, args [][]byte) error

// Structure to hold the necessary information to run a generic Redis
// server
type Server struct {
	ln       net.Listener
	handlers map[string]Handler
}

// Returns a new Server that listen in the specified network address
func NewServer(network, address string) (s Server, err error) {
	s.handlers = make(map[string]Handler)
	s.ln, err = net.Listen(network, address)
	return
}

// Closes a Redis server and stop processing
func (s *Server) Close() error {
	return s.ln.Close()
}

// Add a command handler
//
// Note that this function does not validate that the command is a
// valid Redis command, nor that the command hasn't already a handler.
func (s *Server) Handle(cmd string, handler Handler) {
	cmd = strings.ToUpper(cmd)
	s.handlers[cmd] = handler
}

// Goroutine to process data from a Client
func (s *Server) process(c *Client) {
	defer c.Close()

	for {
		in, err := c.Read()
		if err != nil {
			if err != io.EOF {
				c.Error(err)
			}
			return
		}

		cmd := strings.ToUpper(string(in[0]))

		if fn := s.handlers[cmd]; fn != nil {
			err = fn(c, in[1:])

			if err != nil {
				fmt.Printf("Unexpected error while processing connection: %v\n", err)
			}
		} else {
			c.Errorf("Unrecognized command '%s'", in[0])
		}
	}
}

// Main event loop for Redis clients
func (s *Server) Loop() {
	for {
		c, err := s.ln.Accept()
		if err != nil {
			fmt.Printf("Error while accepting a connection: %v\n", err)
			continue
		}
		client := &Client{s, &c}
		go s.process(client)
	}
}
<commit_msg>Remove duplicated function readLength in server<commit_after>/*
Copyright (c) 2013 Leandro López

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.
*/

/*
gedis server - Generic Redis server implementation

This package allows to create servers that can talk to clients by
using the Redis protocol

Redis protocol: http://redis.io/topics/protocol

As an example, the following implements a very simple Redis server
that only responds to the PING command:

    package main

    import (
    	"fmt"
    	gedis "github.com/inkel/gedis/server"
    	"os"
    	"os/signal"
    )

    func main() {
    	c := make(chan os.Signal, 1)
    	signal.Notify(c, os.Interrupt, os.Kill)

    	s, err := gedis.NewServer("tcp", ":10003")
    	if err != nil {
    		panic(err)
    	}
    	defer s.Close()

    	pong := []byte("+PONG\r\n")
    	earg := []byte("-ERR wrong number of arguments for 'ping' command\r\n")

    	s.Handle("PING", func(c *gedis.Client, args []string) error {
    		if len(args) != 0 {
    			c.Write(earg)
    			return nil
    		} else {
    			c.Write(pong)
    		}

    		return nil
    	})

    	go s.Loop()

    	sig := <-c

    	fmt.Println("Bye!", sig)
    }
*/
package server

import (
	"fmt"
	"github.com/inkel/gedis"
	"io"
	"net"
	"strings"
)

// Interface for reading from Redis clients
type Reader interface {
	Read([]byte) (int, error)
}

// Read a bulk as defined in the Redis protocol
func readBulk(r Reader) (bs []byte, err error) {
	var b byte

	b, err = readByte(r)
	if err != nil {
		return bs, err
	} else if b != '$' {
		return bs, gedis.NewParseError("Invalid first character")
	}

	n, err := gedis.ReadNumber(r)
	if err != nil {
		return bs, err
	}

	bs = make([]byte, n)

	_, err = r.Read(bs)
	if err != nil {
		return bs, err
	}

	crlf := make([]byte, 2)

	if _, err = r.Read(crlf); err != nil {
		return bs, err
	}

	if crlf[0] != '\r' || crlf[1] != '\n' {
		return bs, gedis.NewParseError("Invalid EOL")
	}

	return
}

// Reads the next byte in Reader
func readByte(r Reader) (byte, error) {
	b := make([]byte, 1)
	_, err := r.Read(b)
	return b[0], err
}

// Read a multi-bulk request from a Redis client
//
// Redis client can only send multi-bulk requests to a Redis
// server. In truth they can also send an inline request, however that
// is currently not covered by this implementation
func Read(r Reader) (res [][]byte, err error) {
	var b byte

	b, err = readByte(r)
	if err != nil {
		return
	}

	if b != '*' {
		return res, gedis.NewParseError("Invalid first character")
	} else {
		n, err := gedis.ReadNumber(r)
		if err != nil {
			return res, err
		}

		res = make([][]byte, n)

		for i := int64(0); i < n; i++ {
			res[i], err = readBulk(r)
			if err != nil {
				return res, err
			}
		}
	}

	return res, err
}

// Holds pointers to the current Server and client net.Conn
type Client struct {
	server *Server
	conn   *net.Conn
}

// Disconnects a client
func (c *Client) Close() {
	conn := *c.conn
	conn.Close()
}

// Read from the client, parsing the input with the Redis protocol
func (c *Client) Read() ([][]byte, error) {
	return Read(*c.conn)
}

// Send a sequence of bytes to a client
func (c *Client) Write(bytes []byte) (int, error) {
	conn := *c.conn
	return conn.Write(bytes)
}

// Sends an error to the client, formatted accordingly to the Redis
// protocol
func (c *Client) Error(err error) (int, error) {
	return c.Write(gedis.WriteError(err))
}

// Sends a string formatted as an error to the client
func (c *Client) Errorf(format string, args ...interface{}) (int, error) {
	return c.Error(fmt.Errorf(format, args...))
}

// Sends a status response, formatted accordingly to the Redis
// protocol
func (c *Client) Status(status string) (int, error) {
	return c.Write(gedis.WriteStatus(status))
}

// Signature that command handler functions must have
type Handler func(c *Client, args [][]byte) error

// Structure to hold the necessary information to run a generic Redis
// server
type Server struct {
	ln       net.Listener
	handlers map[string]Handler
}

// Returns a new Server that listen in the specified network address
func NewServer(network, address string) (s Server, err error) {
	s.handlers = make(map[string]Handler)
	s.ln, err = net.Listen(network, address)
	return
}

// Closes a Redis server and stop processing
func (s *Server) Close() error {
	return s.ln.Close()
}

// Add a command handler
//
// Note that this function does not validate that the command is a
// valid Redis command, nor that the command hasn't already a handler.
func (s *Server) Handle(cmd string, handler Handler) {
	cmd = strings.ToUpper(cmd)
	s.handlers[cmd] = handler
}

// Goroutine to process data from a Client
func (s *Server) process(c *Client) {
	defer c.Close()

	for {
		in, err := c.Read()
		if err != nil {
			if err != io.EOF {
				c.Error(err)
			}
			return
		}

		cmd := strings.ToUpper(string(in[0]))

		if fn := s.handlers[cmd]; fn != nil {
			err = fn(c, in[1:])

			if err != nil {
				fmt.Printf("Unexpected error while processing connection: %v\n", err)
			}
		} else {
			c.Errorf("Unrecognized command '%s'", in[0])
		}
	}
}

// Main event loop for Redis clients
func (s *Server) Loop() {
	for {
		c, err := s.ln.Accept()
		if err != nil {
			fmt.Printf("Error while accepting a connection: %v\n", err)
			continue
		}
		client := &Client{s, &c}
		go s.process(client)
	}
}
<|endoftext|>


<commit_before>// Copyright 2017-2018 Authors of Cilium
//
// 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 utils

import (
	"fmt"

	k8sConst "github.com/cilium/cilium/pkg/k8s/apis/cilium.io"
	"github.com/cilium/cilium/pkg/labels"
	"github.com/cilium/cilium/pkg/logging"
	"github.com/cilium/cilium/pkg/logging/logfields"
	"github.com/cilium/cilium/pkg/policy/api"

	"github.com/sirupsen/logrus"
	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const (
	// subsysK8s is the value for logfields.LogSubsys
	subsysK8s = "k8s"
	// podPrefixLbl is the value the prefix used in the label selector to
	// represent pods on the default namespace.
	podPrefixLbl = labels.LabelSourceK8sKeyPrefix + k8sConst.PodNamespaceLabel
)

var (
	// log is the k8s package logger object.
	log = logging.DefaultLogger.WithField(logfields.LogSubsys, subsysK8s)
)

// ExtractNamespace extracts the namespace of ObjectMeta.
func ExtractNamespace(np *metav1.ObjectMeta) string {
	if np.Namespace == "" {
		return v1.NamespaceDefault
	}

	return np.Namespace
}

// GetObjNamespaceName returns the object's namespace and name.
func GetObjNamespaceName(obj *metav1.ObjectMeta) string {
	return ExtractNamespace(obj) + "/" + obj.GetName()
}

// GetPolicyLabels returns a LabelArray for the given namespace and name.
func GetPolicyLabels(ns, name string) labels.LabelArray {
	return labels.ParseLabelArray(
		fmt.Sprintf("%s=%s", k8sConst.PolicyLabelName, name),
		fmt.Sprintf("%s=%s", k8sConst.PolicyLabelNamespace, ns),
	)
}

func parseToCiliumIngressRule(namespace string, inRule, retRule *api.Rule) {
	if inRule.Ingress != nil {
		retRule.Ingress = make([]api.IngressRule, len(inRule.Ingress))
		for i, ing := range inRule.Ingress {
			if ing.FromEndpoints != nil {
				retRule.Ingress[i].FromEndpoints = make([]api.EndpointSelector, len(ing.FromEndpoints))
				for j, ep := range ing.FromEndpoints {
					retRule.Ingress[i].FromEndpoints[j] = api.NewESFromK8sLabelSelector("", ep.LabelSelector)
					if retRule.Ingress[i].FromEndpoints[j].MatchLabels == nil {
						retRule.Ingress[i].FromEndpoints[j].MatchLabels = map[string]string{}
					}
					// There's no need to prefixed K8s
					// prefix for reserved labels
					if retRule.Ingress[i].FromEndpoints[j].HasKeyPrefix(labels.LabelSourceReservedKeyPrefix) {
						continue
					}
					// The user can explicitly specify the namespace in the
					// FromEndpoints selector. If omitted, we limit the
					// scope to the namespace the policy lives in.
					if !retRule.Ingress[i].FromEndpoints[j].HasKey(podPrefixLbl) {
						retRule.Ingress[i].FromEndpoints[j].MatchLabels[podPrefixLbl] = namespace
					}
				}
			}

			if ing.ToPorts != nil {
				retRule.Ingress[i].ToPorts = make([]api.PortRule, len(ing.ToPorts))
				copy(retRule.Ingress[i].ToPorts, ing.ToPorts)
			}
			if ing.FromCIDR != nil {
				retRule.Ingress[i].FromCIDR = make([]api.CIDR, len(ing.FromCIDR))
				copy(retRule.Ingress[i].FromCIDR, ing.FromCIDR)
			}

			if ing.FromCIDRSet != nil {
				retRule.Ingress[i].FromCIDRSet = make([]api.CIDRRule, len(ing.FromCIDRSet))
				copy(retRule.Ingress[i].FromCIDRSet, ing.FromCIDRSet)
			}

			if ing.FromRequires != nil {
				retRule.Ingress[i].FromRequires = make([]api.EndpointSelector, len(ing.FromRequires))
				for j, ep := range ing.FromRequires {
					retRule.Ingress[i].FromRequires[j] = api.NewESFromK8sLabelSelector("", ep.LabelSelector)
					if retRule.Ingress[i].FromRequires[j].MatchLabels == nil {
						retRule.Ingress[i].FromRequires[j].MatchLabels = map[string]string{}
					}
					// The user can explicitly specify the namespace in the
					// FromEndpoints selector. If omitted, we limit the
					// scope to the namespace the policy lives in.
					if !retRule.Ingress[i].FromRequires[j].HasKey(podPrefixLbl) {
						retRule.Ingress[i].FromRequires[j].MatchLabels[podPrefixLbl] = namespace
					}
				}
			}

			if ing.FromEntities != nil {
				retRule.Ingress[i].FromEntities = make([]api.Entity, len(ing.FromEntities))
				copy(retRule.Ingress[i].FromEntities, ing.FromEntities)
			}
		}
	}
}

func parseToCiliumEgressRule(namespace string, inRule, retRule *api.Rule) {
	if inRule.Egress != nil {
		retRule.Egress = make([]api.EgressRule, len(inRule.Egress))

		for i, egr := range inRule.Egress {
			if egr.ToEndpoints != nil {
				retRule.Egress[i].ToEndpoints = make([]api.EndpointSelector, len(egr.ToEndpoints))
				for j, ep := range egr.ToEndpoints {
					retRule.Egress[i].ToEndpoints[j] = api.NewESFromK8sLabelSelector("", ep.LabelSelector)
					if retRule.Egress[i].ToEndpoints[j].MatchLabels == nil {
						retRule.Egress[i].ToEndpoints[j].MatchLabels = map[string]string{}
					}
					// There's no need to add K8s prefix for reserved labels
					if retRule.Egress[i].ToEndpoints[j].HasKeyPrefix(labels.LabelSourceReservedKeyPrefix) {
						continue
					}
					// The user can explicitly specify the namespace in the
					// ToEndpoints selector. If omitted, we limit the
					// scope to the namespace the policy lives in.
					if !retRule.Egress[i].ToEndpoints[j].HasKey(podPrefixLbl) {
						retRule.Egress[i].ToEndpoints[j].MatchLabels[podPrefixLbl] = namespace
					}
				}
			}

			if egr.ToPorts != nil {
				retRule.Egress[i].ToPorts = make([]api.PortRule, len(egr.ToPorts))
				copy(retRule.Egress[i].ToPorts, egr.ToPorts)
			}
			if egr.ToCIDR != nil {
				retRule.Egress[i].ToCIDR = make([]api.CIDR, len(egr.ToCIDR))
				copy(retRule.Egress[i].ToCIDR, egr.ToCIDR)
			}

			if egr.ToCIDRSet != nil {
				retRule.Egress[i].ToCIDRSet = make(api.CIDRRuleSlice, len(egr.ToCIDRSet))
				copy(retRule.Egress[i].ToCIDRSet, egr.ToCIDRSet)
			}

			if egr.ToRequires != nil {
				retRule.Egress[i].ToRequires = make([]api.EndpointSelector, len(egr.ToRequires))
				for j, ep := range egr.ToRequires {
					retRule.Egress[i].ToRequires[j] = api.NewESFromK8sLabelSelector("", ep.LabelSelector)
					if retRule.Egress[i].ToRequires[j].MatchLabels == nil {
						retRule.Egress[i].ToRequires[j].MatchLabels = map[string]string{}
					}
					// The user can explicitly specify the namespace in the
					// ToEndpoints selector. If omitted, we limit the
					// scope to the namespace the policy lives in.
					if !retRule.Egress[i].ToRequires[j].HasKey(podPrefixLbl) {
						retRule.Egress[i].ToRequires[j].MatchLabels[podPrefixLbl] = namespace
					}
				}
			}

			if egr.ToServices != nil {
				retRule.Egress[i].ToServices = make([]api.Service, len(egr.ToServices))
				copy(retRule.Egress[i].ToServices, egr.ToServices)
			}

			if egr.ToEntities != nil {
				retRule.Egress[i].ToEntities = make([]api.Entity, len(egr.ToEntities))
				copy(retRule.Egress[i].ToEntities, egr.ToEntities)
			}
		}
	}
}

// ParseToCiliumRule returns an api.Rule with all the labels parsed into cilium
// labels.
func ParseToCiliumRule(namespace, name string, r *api.Rule) *api.Rule {
	retRule := &api.Rule{}
	if r.EndpointSelector.LabelSelector != nil {
		retRule.EndpointSelector = api.NewESFromK8sLabelSelector("", r.EndpointSelector.LabelSelector)
		// The PodSelector should only reflect to the same namespace
		// the policy is being stored, thus we add the namespace to
		// the MatchLabels map.
		if retRule.EndpointSelector.LabelSelector.MatchLabels == nil {
			retRule.EndpointSelector.LabelSelector.MatchLabels = map[string]string{}
		}

		userNamespace, ok := retRule.EndpointSelector.LabelSelector.MatchLabels[podPrefixLbl]
		if ok && userNamespace != namespace {
			log.WithFields(logrus.Fields{
				logfields.K8sNamespace:              namespace,
				logfields.CiliumNetworkPolicyName:   name,
				logfields.K8sNamespace + ".illegal": userNamespace,
			}).Warn("CiliumNetworkPolicy contains illegal namespace match in EndpointSelector." +
				" EndpointSelector always applies in namespace of the policy resource, removing illegal namespace match'.")
		}
		retRule.EndpointSelector.LabelSelector.MatchLabels[podPrefixLbl] = namespace
	}

	parseToCiliumIngressRule(namespace, r, retRule)
	parseToCiliumEgressRule(namespace, r, retRule)

	policyLbls := GetPolicyLabels(namespace, name)
	if retRule.Labels == nil {
		retRule.Labels = make(labels.LabelArray, 0, len(policyLbls)+len(r.Labels))
	}
	retRule.Labels = append(retRule.Labels, policyLbls...)
	retRule.Labels = append(retRule.Labels, r.Labels...)

	retRule.Description = r.Description

	return retRule
}
<commit_msg>k8s: Don't add namespace labels into reserved:init endpoint selectors<commit_after>// Copyright 2017-2018 Authors of Cilium
//
// 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 utils

import (
	"fmt"

	k8sConst "github.com/cilium/cilium/pkg/k8s/apis/cilium.io"
	"github.com/cilium/cilium/pkg/labels"
	"github.com/cilium/cilium/pkg/logging"
	"github.com/cilium/cilium/pkg/logging/logfields"
	"github.com/cilium/cilium/pkg/policy/api"

	"github.com/sirupsen/logrus"
	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const (
	// subsysK8s is the value for logfields.LogSubsys
	subsysK8s = "k8s"
	// podPrefixLbl is the value the prefix used in the label selector to
	// represent pods on the default namespace.
	podPrefixLbl = labels.LabelSourceK8sKeyPrefix + k8sConst.PodNamespaceLabel

	// podInitLbl is the label used in a label selector to match on
	// initializing pods.
	podInitLbl = labels.LabelSourceReservedKeyPrefix + labels.IDNameInit
)

var (
	// log is the k8s package logger object.
	log = logging.DefaultLogger.WithField(logfields.LogSubsys, subsysK8s)
)

// ExtractNamespace extracts the namespace of ObjectMeta.
func ExtractNamespace(np *metav1.ObjectMeta) string {
	if np.Namespace == "" {
		return v1.NamespaceDefault
	}

	return np.Namespace
}

// GetObjNamespaceName returns the object's namespace and name.
func GetObjNamespaceName(obj *metav1.ObjectMeta) string {
	return ExtractNamespace(obj) + "/" + obj.GetName()
}

// GetPolicyLabels returns a LabelArray for the given namespace and name.
func GetPolicyLabels(ns, name string) labels.LabelArray {
	return labels.ParseLabelArray(
		fmt.Sprintf("%s=%s", k8sConst.PolicyLabelName, name),
		fmt.Sprintf("%s=%s", k8sConst.PolicyLabelNamespace, ns),
	)
}

func parseToCiliumIngressRule(namespace string, inRule, retRule *api.Rule) {
	if inRule.Ingress != nil {
		retRule.Ingress = make([]api.IngressRule, len(inRule.Ingress))
		for i, ing := range inRule.Ingress {
			if ing.FromEndpoints != nil {
				retRule.Ingress[i].FromEndpoints = make([]api.EndpointSelector, len(ing.FromEndpoints))
				for j, ep := range ing.FromEndpoints {
					retRule.Ingress[i].FromEndpoints[j] = api.NewESFromK8sLabelSelector("", ep.LabelSelector)
					if retRule.Ingress[i].FromEndpoints[j].MatchLabels == nil {
						retRule.Ingress[i].FromEndpoints[j].MatchLabels = map[string]string{}
					}
					// There's no need to prefixed K8s
					// prefix for reserved labels
					if retRule.Ingress[i].FromEndpoints[j].HasKeyPrefix(labels.LabelSourceReservedKeyPrefix) {
						continue
					}
					// The user can explicitly specify the namespace in the
					// FromEndpoints selector. If omitted, we limit the
					// scope to the namespace the policy lives in.
					//
					// Policies applying on initializing pods are a special case.
					// Those pods don't have any labels, so they don't have a namespace label either.
					// Don't add a namespace label to those endpoint selectors, or we wouldn't be
					// able to match on those pods.
					if _, ok := retRule.EndpointSelector.LabelSelector.MatchLabels[podInitLbl]; !ok &&
						!retRule.Ingress[i].FromEndpoints[j].HasKey(podPrefixLbl) {
						retRule.Ingress[i].FromEndpoints[j].MatchLabels[podPrefixLbl] = namespace
					}
				}
			}

			if ing.ToPorts != nil {
				retRule.Ingress[i].ToPorts = make([]api.PortRule, len(ing.ToPorts))
				copy(retRule.Ingress[i].ToPorts, ing.ToPorts)
			}
			if ing.FromCIDR != nil {
				retRule.Ingress[i].FromCIDR = make([]api.CIDR, len(ing.FromCIDR))
				copy(retRule.Ingress[i].FromCIDR, ing.FromCIDR)
			}

			if ing.FromCIDRSet != nil {
				retRule.Ingress[i].FromCIDRSet = make([]api.CIDRRule, len(ing.FromCIDRSet))
				copy(retRule.Ingress[i].FromCIDRSet, ing.FromCIDRSet)
			}

			if ing.FromRequires != nil {
				retRule.Ingress[i].FromRequires = make([]api.EndpointSelector, len(ing.FromRequires))
				for j, ep := range ing.FromRequires {
					retRule.Ingress[i].FromRequires[j] = api.NewESFromK8sLabelSelector("", ep.LabelSelector)
					if retRule.Ingress[i].FromRequires[j].MatchLabels == nil {
						retRule.Ingress[i].FromRequires[j].MatchLabels = map[string]string{}
					}
					// The user can explicitly specify the namespace in the
					// FromEndpoints selector. If omitted, we limit the
					// scope to the namespace the policy lives in.
					//
					// Policies applying on initializing pods are a special case.
					// Those pods don't have any labels, so they don't have a namespace label either.
					// Don't add a namespace label to those endpoint selectors, or we wouldn't be
					// able to match on those pods.
					if _, ok := retRule.EndpointSelector.LabelSelector.MatchLabels[podInitLbl]; !ok &&
						!retRule.Ingress[i].FromRequires[j].HasKey(podPrefixLbl) {
						retRule.Ingress[i].FromRequires[j].MatchLabels[podPrefixLbl] = namespace
					}
				}
			}

			if ing.FromEntities != nil {
				retRule.Ingress[i].FromEntities = make([]api.Entity, len(ing.FromEntities))
				copy(retRule.Ingress[i].FromEntities, ing.FromEntities)
			}
		}
	}
}

func parseToCiliumEgressRule(namespace string, inRule, retRule *api.Rule) {
	if inRule.Egress != nil {
		retRule.Egress = make([]api.EgressRule, len(inRule.Egress))

		for i, egr := range inRule.Egress {
			if egr.ToEndpoints != nil {
				retRule.Egress[i].ToEndpoints = make([]api.EndpointSelector, len(egr.ToEndpoints))
				for j, ep := range egr.ToEndpoints {
					retRule.Egress[i].ToEndpoints[j] = api.NewESFromK8sLabelSelector("", ep.LabelSelector)
					if retRule.Egress[i].ToEndpoints[j].MatchLabels == nil {
						retRule.Egress[i].ToEndpoints[j].MatchLabels = map[string]string{}
					}
					// There's no need to add K8s prefix for reserved labels
					if retRule.Egress[i].ToEndpoints[j].HasKeyPrefix(labels.LabelSourceReservedKeyPrefix) {
						continue
					}
					// The user can explicitly specify the namespace in the
					// ToEndpoints selector. If omitted, we limit the
					// scope to the namespace the policy lives in.
					//
					// Policies applying on initializing pods are a special case.
					// Those pods don't have any labels, so they don't have a namespace label either.
					// Don't add a namespace label to those endpoint selectors, or we wouldn't be
					// able to match on those pods.
					if _, ok := retRule.EndpointSelector.LabelSelector.MatchLabels[podInitLbl]; !ok &&
						!retRule.Egress[i].ToEndpoints[j].HasKey(podPrefixLbl) {
						retRule.Egress[i].ToEndpoints[j].MatchLabels[podPrefixLbl] = namespace
					}
				}
			}

			if egr.ToPorts != nil {
				retRule.Egress[i].ToPorts = make([]api.PortRule, len(egr.ToPorts))
				copy(retRule.Egress[i].ToPorts, egr.ToPorts)
			}
			if egr.ToCIDR != nil {
				retRule.Egress[i].ToCIDR = make([]api.CIDR, len(egr.ToCIDR))
				copy(retRule.Egress[i].ToCIDR, egr.ToCIDR)
			}

			if egr.ToCIDRSet != nil {
				retRule.Egress[i].ToCIDRSet = make(api.CIDRRuleSlice, len(egr.ToCIDRSet))
				copy(retRule.Egress[i].ToCIDRSet, egr.ToCIDRSet)
			}

			if egr.ToRequires != nil {
				retRule.Egress[i].ToRequires = make([]api.EndpointSelector, len(egr.ToRequires))
				for j, ep := range egr.ToRequires {
					retRule.Egress[i].ToRequires[j] = api.NewESFromK8sLabelSelector("", ep.LabelSelector)
					if retRule.Egress[i].ToRequires[j].MatchLabels == nil {
						retRule.Egress[i].ToRequires[j].MatchLabels = map[string]string{}
					}
					// The user can explicitly specify the namespace in the
					// ToEndpoints selector. If omitted, we limit the
					// scope to the namespace the policy lives in.
					//
					// Policies applying on initializing pods are a special case.
					// Those pods don't have any labels, so they don't have a namespace label either.
					// Don't add a namespace label to those endpoint selectors, or we wouldn't be
					// able to match on those pods.
					if _, ok := retRule.EndpointSelector.LabelSelector.MatchLabels[podInitLbl]; !ok &&
						!retRule.Egress[i].ToRequires[j].HasKey(podPrefixLbl) {
						retRule.Egress[i].ToRequires[j].MatchLabels[podPrefixLbl] = namespace
					}
				}
			}

			if egr.ToServices != nil {
				retRule.Egress[i].ToServices = make([]api.Service, len(egr.ToServices))
				copy(retRule.Egress[i].ToServices, egr.ToServices)
			}

			if egr.ToEntities != nil {
				retRule.Egress[i].ToEntities = make([]api.Entity, len(egr.ToEntities))
				copy(retRule.Egress[i].ToEntities, egr.ToEntities)
			}
		}
	}
}

// ParseToCiliumRule returns an api.Rule with all the labels parsed into cilium
// labels.
func ParseToCiliumRule(namespace, name string, r *api.Rule) *api.Rule {
	retRule := &api.Rule{}
	if r.EndpointSelector.LabelSelector != nil {
		retRule.EndpointSelector = api.NewESFromK8sLabelSelector("", r.EndpointSelector.LabelSelector)
		// The PodSelector should only reflect to the same namespace
		// the policy is being stored, thus we add the namespace to
		// the MatchLabels map.
		if retRule.EndpointSelector.LabelSelector.MatchLabels == nil {
			retRule.EndpointSelector.LabelSelector.MatchLabels = map[string]string{}
		}

		// Policies applying on initializing pods are a special case.
		// Those pods don't have any labels, so they don't have a namespace label either.
		// Don't add a namespace label to those endpoint selectors, or we wouldn't be
		// able to match on those pods.
		if _, ok := retRule.EndpointSelector.LabelSelector.MatchLabels[podInitLbl]; !ok {
			userNamespace, ok := retRule.EndpointSelector.LabelSelector.MatchLabels[podPrefixLbl]
			if ok && userNamespace != namespace {
				log.WithFields(logrus.Fields{
					logfields.K8sNamespace:              namespace,
					logfields.CiliumNetworkPolicyName:   name,
					logfields.K8sNamespace + ".illegal": userNamespace,
				}).Warn("CiliumNetworkPolicy contains illegal namespace match in EndpointSelector." +
					" EndpointSelector always applies in namespace of the policy resource, removing illegal namespace match'.")
			}
			retRule.EndpointSelector.LabelSelector.MatchLabels[podPrefixLbl] = namespace
		}
	}

	parseToCiliumIngressRule(namespace, r, retRule)
	parseToCiliumEgressRule(namespace, r, retRule)

	policyLbls := GetPolicyLabels(namespace, name)
	if retRule.Labels == nil {
		retRule.Labels = make(labels.LabelArray, 0, len(policyLbls)+len(r.Labels))
	}
	retRule.Labels = append(retRule.Labels, policyLbls...)
	retRule.Labels = append(retRule.Labels, r.Labels...)

	retRule.Description = r.Description

	return retRule
}
<|endoftext|>