<commit_before>package ofutils

import (
	"bufio"
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"math/rand"
	"net"
	"net/smtp"
	"os"
	"reflect"
	"sort"
	"strconv"
	"strings"
	"time"

	"golang.org/x/text/encoding/simplifiedchinese"
	"golang.org/x/text/transform"

	"github.com/astaxie/beego/orm"
	"github.com/axgle/mahonia"
)

func init() {
	rand.Seed(time.Now().UnixNano())
}

var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

func RandString(n int) string {
	b := make([]rune, n)
	for i := range b {
		b[i] = letterRunes[rand.Intn(len(letterRunes))]
	}
	return string(b)
}
func ChangeJson(data *[]byte, key string, value interface{}) error {
	var m map[string]interface{}
	err := json.Unmarshal(*data, &m)
	if err != nil {
		return err
	}
	m[key] = value
	*data, err = json.Marshal(m)
	return err
}
func MD5(text string) string {
	hasher := md5.New()
	hasher.Write([]byte(text))
	return hex.EncodeToString(hasher.Sum(nil))
}

func ToString(str interface{}) string {
	if str == nil {
		return ""
	}
	return fmt.Sprintf("%v", str)
}

func ToInt(val interface{}) int {
	if val == nil {
		return 0
	}
	s, ok := val.(string)
	if ok {
		i, err := strconv.Atoi(s)
		if err != nil {
			return 0
		}
		return i
	}
	i, ok := val.(int)
	if ok {
		return i
	} else {
		return 0
	}
}

func GetWeekFirstDay() string {
	week := time.Now().Weekday().String()
	var day time.Duration
	switch week {
	case "Sunday":
		day = 6
		break
	case "Monday":
		day = 0
		break
	case "Tuesday":
		day = 1
		break
	case "Wednesday":
		day = 2
		break
	case "Thursday":
		day = 3
		break
	case "Friday":
		day = 4
		break
	case "Saturday":
		day = 5
		break
	}
	date := time.Now().Add(-day * 24 * time.Hour)
	return date.Format("2006-01-02")
}

type ByKey struct {
	Key  string
	List []orm.Params
}

func (a ByKey) Len() int {
	return len(a.List)
}
func (a ByKey) Swap(i, j int) {
	a.List[i], a.List[j] = a.List[j], a.List[i]
}
func (a ByKey) Less(i, j int) bool {
	return ToInt(a.List[i][a.Key]) > ToInt(a.List[j][a.Key])
}

func Sort(list []orm.Params, key string) []orm.Params {
	byKey := ByKey{List: list, Key: key}
	sort.Sort(byKey)
	return byKey.List
}

func SubString(str string, begin, length int) (substr string) {
	// 将字符串的转换成[]rune
	rs := []rune(str)
	lth := len(rs)

	// 简单的越界判断
	if begin < 0 {
		begin = 0
	}
	if begin >= lth {
		begin = lth
	}
	end := begin + length
	if end > lth {
		end = lth
	}
	// 返回子串
	return string(rs[begin:end])
}

func ToFloat(str interface{}) float64 {
	if str == nil {
		return 0
	}
	tf, err := strconv.ParseFloat(ToString(str), 64)
	if err != nil {
		return 0
	}
	return tf
}
func ToJson(datas interface{}) string {
	jsonString, _ := json.Marshal(datas)
	return string(jsonString)
}
func GetEncryptPhone(phone interface{}) string {
	temp := ToString(phone)
	if len(temp) == 11 {
		start := SubString(temp, 0, 3)
		end := SubString(temp, 7, 11)
		temp = start + "****" + end
	}
	return temp
}
func Exist(filename string) bool {
	_, err := os.Stat(filename)
	return err == nil || os.IsExist(err)
}
func SendMail(user, password, host, to, subject, body, mailtype string) error {
	hp := strings.Split(host, ":")
	auth := smtp.PlainAuth("", user, password, hp[0])
	var content_type string
	if mailtype == "html" {
		content_type = "Content-Type: text/" + mailtype + "; charset=UTF-8"
	} else {
		content_type = "Content-Type: text/plain" + "; charset=UTF-8"
	}

	msg := []byte("To: " + to + "\r\nFrom: " + user + "<" + user + ">\r\nSubject: " + subject + "\r\n" + content_type + "\r\n\r\n" + body)
	send_to := strings.Split(to, ";")
	err := smtp.SendMail(host, auth, user, send_to, msg)
	return err
}
func ZeroBefore(i int) string {
	if i < 10 {
		return "0" + ToString(i)
	}
	return ToString(i)
}
func GetTimeStamp() string {
	return time.Now().Format("20060102150405")
}
func Utf8ToGBK(text string) string {
	enc := mahonia.NewEncoder("gbk")
	return enc.ConvertString(text)
}
func GBKFileToUtf8(filePath string) string {
	// Read UTF-8 from a GBK encoded file.
	f, err := os.Open(filePath)
	if err != nil {
		log.Fatal(err)
	}
	r := transform.NewReader(f, simplifiedchinese.GBK.NewDecoder())

	// Read converted UTF-8 from `r` as needed.
	// As an example we'll read line-by-line showing what was read:
	sc := bufio.NewScanner(r)
	result := ""
	for sc.Scan() {
		result += string(sc.Bytes()) + "\n"
	}
	return result
}
func TrimSuffix(s, suffix string) string {
	if strings.HasSuffix(s, suffix) {
		s = s[:len(s)-len(suffix)]
	}
	return s
}
func TrimPrefix(s, suffix string) string {
	if strings.HasPrefix(s, suffix) {
		s = s[len(suffix):]
	}
	return s
}
func Copy(dst, src string) error {
	in, err := os.Open(src)
	if err != nil {
		return err
	}
	defer in.Close()
	out, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer out.Close()
	_, err = io.Copy(out, in)
	cerr := out.Close()
	if err != nil {
		return err
	}
	return cerr
}

func GetStructName(myvar interface{}) string {
	if t := reflect.TypeOf(myvar); t.Kind() == reflect.Ptr {
		return t.Elem().Name()
	} else {
		return t.Name()
	}
}

func ByteToMapArray(data [][]byte) []map[string]interface{} {
	list := make([]map[string]interface{}, len(data))
	for i, v := range data {
		json.Unmarshal(v, &list[i])
	}
	return list
}

func GetOutboundIP() string {
	conn, err := net.Dial("udp", "8.8.8.8:80")
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()

	localAddr := conn.LocalAddr().(*net.UDPAddr)

	return localAddr.IP.String()
}
<commit_msg>update<commit_after>package ofutils

import (
	"bufio"
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"math/rand"
	"net"
	"net/smtp"
	"os"
	"reflect"
	"sort"
	"strconv"
	"strings"
	"time"

	"golang.org/x/text/encoding/simplifiedchinese"
	"golang.org/x/text/transform"

	"github.com/astaxie/beego/orm"
	"github.com/axgle/mahonia"
)

func init() {
	rand.Seed(time.Now().UnixNano())
}

var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

func RandString(n int) string {
	b := make([]rune, n)
	for i := range b {
		b[i] = letterRunes[rand.Intn(len(letterRunes))]
	}
	return string(b)
}
func ChangeJson(data *[]byte, key string, value interface{}) error {
	var m map[string]interface{}
	err := json.Unmarshal(*data, &m)
	if err != nil {
		return err
	}
	m[key] = value
	*data, err = json.Marshal(m)
	return err
}
func MD5(text string) string {
	hasher := md5.New()
	hasher.Write([]byte(text))
	return hex.EncodeToString(hasher.Sum(nil))
}

func ToString(str interface{}) string {
	if str == nil {
		return ""
	}
	return fmt.Sprintf("%v", str)
}

func ToInt(val interface{}) int {
	if val == nil {
		return 0
	}
	s, ok := val.(string)
	if ok {
		i, err := strconv.Atoi(s)
		if err != nil {
			return 0
		}
		return i
	}
	i, ok := val.(int)
	if ok {
		return i
	} else {
		return 0
	}
}

func GetWeekFirstDay() string {
	week := time.Now().Weekday().String()
	var day time.Duration
	switch week {
	case "Sunday":
		day = 6
		break
	case "Monday":
		day = 0
		break
	case "Tuesday":
		day = 1
		break
	case "Wednesday":
		day = 2
		break
	case "Thursday":
		day = 3
		break
	case "Friday":
		day = 4
		break
	case "Saturday":
		day = 5
		break
	}
	date := time.Now().Add(-day * 24 * time.Hour)
	return date.Format("2006-01-02")
}

type ByKey struct {
	Key  string
	List []orm.Params
}

func (a ByKey) Len() int {
	return len(a.List)
}
func (a ByKey) Swap(i, j int) {
	a.List[i], a.List[j] = a.List[j], a.List[i]
}
func (a ByKey) Less(i, j int) bool {
	return ToInt(a.List[i][a.Key]) > ToInt(a.List[j][a.Key])
}

func Sort(list []orm.Params, key string) []orm.Params {
	byKey := ByKey{List: list, Key: key}
	sort.Sort(byKey)
	return byKey.List
}

func SubString(str string, begin, length int) (substr string) {
	// 将字符串的转换成[]rune
	rs := []rune(str)
	lth := len(rs)

	// 简单的越界判断
	if begin < 0 {
		begin = 0
	}
	if begin >= lth {
		begin = lth
	}
	end := begin + length
	if end > lth {
		end = lth
	}
	// 返回子串
	return string(rs[begin:end])
}

func ToFloat(str interface{}) float64 {
	if str == nil {
		return 0
	}
	tf, err := strconv.ParseFloat(ToString(str), 64)
	if err != nil {
		return 0
	}
	return tf
}
func ToJson(datas interface{}) string {
	jsonString, _ := json.Marshal(datas)
	return string(jsonString)
}
func GetEncryptPhone(phone interface{}) string {
	temp := ToString(phone)
	if len(temp) == 11 {
		start := SubString(temp, 0, 3)
		end := SubString(temp, 7, 11)
		temp = start + "****" + end
	}
	return temp
}
func Exist(filename string) bool {
	_, err := os.Stat(filename)
	return err == nil || os.IsExist(err)
}
func SendMail(user, password, host, to, subject, body, mailtype string) error {
	hp := strings.Split(host, ":")
	auth := smtp.PlainAuth("", user, password, hp[0])
	var content_type string
	if mailtype == "html" {
		content_type = "Content-Type: text/" + mailtype + "; charset=UTF-8"
	} else {
		content_type = "Content-Type: text/plain" + "; charset=UTF-8"
	}

	msg := []byte("To: " + to + "\r\nFrom: " + user + "<" + user + ">\r\nSubject: " + subject + "\r\n" + content_type + "\r\n\r\n" + body)
	send_to := strings.Split(to, ";")
	err := smtp.SendMail(host, auth, user, send_to, msg)
	return err
}
func ZeroBefore(i int) string {
	if i < 10 {
		return "0" + ToString(i)
	}
	return ToString(i)
}
func GetTimeStamp() string {
	return time.Now().Format("20060102150405")
}
func Utf8ToGBK(text string) string {
	enc := mahonia.NewEncoder("gbk")
	return enc.ConvertString(text)
}
func GBKFileToUtf8(filePath string) string {
	// Read UTF-8 from a GBK encoded file.
	f, err := os.Open(filePath)
	if err != nil {
		log.Fatal(err)
	}
	r := transform.NewReader(f, simplifiedchinese.GBK.NewDecoder())

	// Read converted UTF-8 from `r` as needed.
	// As an example we'll read line-by-line showing what was read:
	sc := bufio.NewScanner(r)
	result := ""
	for sc.Scan() {
		result += string(sc.Bytes()) + "\n"
	}
	return result
}
func TrimSuffix(s, suffix string) string {
	if strings.HasSuffix(s, suffix) {
		s = s[:len(s)-len(suffix)]
	}
	return s
}
func TrimPrefix(s, suffix string) string {
	if strings.HasPrefix(s, suffix) {
		s = s[len(suffix):]
	}
	return s
}
func Copy(dst, src string) error {
	in, err := os.Open(src)
	if err != nil {
		return err
	}
	defer in.Close()
	out, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer out.Close()
	_, err = io.Copy(out, in)
	cerr := out.Close()
	if err != nil {
		return err
	}
	return cerr
}

func GetStructName(myvar interface{}) string {
	if t := reflect.TypeOf(myvar); t.Kind() == reflect.Ptr {
		return t.Elem().Name()
	} else {
		return t.Name()
	}
}

func ByteToMapArray(data [][]byte) []map[string]interface{} {
	list := make([]map[string]interface{}, len(data))
	for i, v := range data {
		json.Unmarshal(v, &list[i])
	}
	return list
}

// GetLocalIP returns the non loopback local IP of the host
func GetLocalIP() string {
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		return ""
	}
	for _, address := range addrs {
		// check the address type and if it is not a loopback the display it
		if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
			if ipnet.IP.To4() != nil {
				return ipnet.IP.String()
			}
		}
	}
	return ""
}
<|endoftext|>


<commit_before>package openssh

import (
	"errors"
	"fmt"
	"sort"
	"strconv"
	"strings"

	"github.com/mlafeldt/chef-runner/exec"
)

type Client struct {
	Host        string
	User        string
	Port        int
	PrivateKeys []string
	Options     map[string]string
}

// NewClient creates a OpenSSH client from the given host string. The host
// string has the format [user@]hostname[:port]
func NewClient(host string) (*Client, error) {
	var user string
	a := strings.Split(host, "@")
	if len(a) > 1 {
		user = a[0]
		host = a[1]
	}

	var port int
	a = strings.Split(host, ":")
	if len(a) > 1 {
		host = a[0]
		var err error
		if port, err = strconv.Atoi(a[1]); err != nil {
			return nil, errors.New("invalid SSH port")
		}
	}

	c := Client{
		Host: host,
		User: user,
		Port: port,
	}
	return &c, nil
}

func (c Client) String() string {
	return fmt.Sprintf("OpenSSH (host: %s)", c.Host)
}

func (c Client) Command(command string) ([]string, error) {
	if command == "" {
		return nil, errors.New("no command given")
	}
	if c.Host == "" {
		return nil, errors.New("no host given")
	}

	cmd := []string{"ssh"}

	if c.User != "" {
		cmd = append(cmd, "-l", c.User)
	}

	if c.Port != 0 {
		cmd = append(cmd, "-p", strconv.Itoa(c.Port))
	}

	for _, pk := range c.PrivateKeys {
		cmd = append(cmd, "-i", pk)
	}

	// Sort options by name before using them
	var optionNames []string
	for k := range c.Options {
		optionNames = append(optionNames, k)
	}
	sort.Strings(optionNames)
	for _, k := range optionNames {
		cmd = append(cmd, "-o", k+"="+c.Options[k])
	}

	cmd = append(cmd, c.Host, command)
	return cmd, nil
}

func (c Client) RunCommand(command string) error {
	cmd, err := c.Command(command)
	if err != nil {
		return err
	}
	return exec.RunCommand(cmd)
}
<commit_msg>Fix typo<commit_after>package openssh

import (
	"errors"
	"fmt"
	"sort"
	"strconv"
	"strings"

	"github.com/mlafeldt/chef-runner/exec"
)

type Client struct {
	Host        string
	User        string
	Port        int
	PrivateKeys []string
	Options     map[string]string
}

// NewClient creates an OpenSSH client from the given host string. The host
// string has the format [user@]hostname[:port]
func NewClient(host string) (*Client, error) {
	var user string
	a := strings.Split(host, "@")
	if len(a) > 1 {
		user = a[0]
		host = a[1]
	}

	var port int
	a = strings.Split(host, ":")
	if len(a) > 1 {
		host = a[0]
		var err error
		if port, err = strconv.Atoi(a[1]); err != nil {
			return nil, errors.New("invalid SSH port")
		}
	}

	c := Client{
		Host: host,
		User: user,
		Port: port,
	}
	return &c, nil
}

func (c Client) String() string {
	return fmt.Sprintf("OpenSSH (host: %s)", c.Host)
}

func (c Client) Command(command string) ([]string, error) {
	if command == "" {
		return nil, errors.New("no command given")
	}
	if c.Host == "" {
		return nil, errors.New("no host given")
	}

	cmd := []string{"ssh"}

	if c.User != "" {
		cmd = append(cmd, "-l", c.User)
	}

	if c.Port != 0 {
		cmd = append(cmd, "-p", strconv.Itoa(c.Port))
	}

	for _, pk := range c.PrivateKeys {
		cmd = append(cmd, "-i", pk)
	}

	// Sort options by name before using them
	var optionNames []string
	for k := range c.Options {
		optionNames = append(optionNames, k)
	}
	sort.Strings(optionNames)
	for _, k := range optionNames {
		cmd = append(cmd, "-o", k+"="+c.Options[k])
	}

	cmd = append(cmd, c.Host, command)
	return cmd, nil
}

func (c Client) RunCommand(command string) error {
	cmd, err := c.Command(command)
	if err != nil {
		return err
	}
	return exec.RunCommand(cmd)
}
<|endoftext|>


<commit_before>package buffalo

import (
	"context"
	"fmt"
	"net/http"
	"strings"

	"github.com/sirupsen/logrus"

	"github.com/fatih/color"
	"github.com/gobuffalo/buffalo/worker"
	"github.com/gobuffalo/envy"
	"github.com/gobuffalo/pop"
	"github.com/gorilla/sessions"
	"github.com/markbates/going/defaults"
)

// Options are used to configure and define how your application should run.
type Options struct {
	Name string
	// Addr is the bind address provided to http.Server. Default is "127.0.0.1:3000"
	// Can be set using ENV vars "ADDR" and "PORT".
	Addr string
	// Host that this application will be available at. Default is "http://127.0.0.1:[$PORT|3000]".
	Host string

	// Env is the "environment" in which the App is running. Default is "development".
	Env string

	// LogLevel defaults to "debug".
	LogLevel string
	// Logger to be used with the application. A default one is provided.
	Logger Logger

	// MethodOverride allows for changing of the request method type. See the default
	// implementation at buffalo.MethodOverride
	MethodOverride http.HandlerFunc

	// SessionStore is the `github.com/gorilla/sessions` store used to back
	// the session. It defaults to use a cookie store and the ENV variable
	// `SESSION_SECRET`.
	SessionStore sessions.Store
	// SessionName is the name of the session cookie that is set. This defaults
	// to "_buffalo_session".
	SessionName string

	// Worker implements the Worker interface and can process tasks in the background.
	// Default is "github.com/gobuffalo/worker.Simple.
	Worker worker.Worker
	// WorkerOff tells App.Start() whether to start the Worker process or not. Default is "false".
	WorkerOff bool

	// PreHandlers are http.Handlers that are called between the http.Server
	// and the buffalo Application.
	PreHandlers []http.Handler
	// PreWare takes an http.Handler and returns and http.Handler
	// and acts as a pseudo-middleware between the http.Server and
	// a Buffalo application.
	PreWares []PreWare

	Context context.Context

	// LooseSlash defines the trailing slash behavior for new routes. The initial value is false.
	// This is the opposite of http://www.gorillatoolkit.org/pkg/mux#Router.StrictSlash
	LooseSlash bool

	cancel context.CancelFunc
	Prefix string
}

// PreWare takes an http.Handler and returns and http.Handler
// and acts as a pseudo-middleware between the http.Server and
// a Buffalo application.
type PreWare func(http.Handler) http.Handler

// NewOptions returns a new Options instance with sensible defaults
func NewOptions() Options {
	return optionsWithDefaults(Options{})
}

func optionsWithDefaults(opts Options) Options {
	opts.Env = defaults.String(opts.Env, envy.Get("GO_ENV", "development"))
	opts.LogLevel = defaults.String(opts.LogLevel, "debug")
	opts.Name = defaults.String(opts.Name, "/")
	addr := "0.0.0.0"
	if opts.Env == "development" {
		addr = "127.0.0.1"
	}
	envAddr := envy.Get("ADDR", addr)

	if strings.HasPrefix(envAddr, "unix:") {
		// UNIX domain socket doesn't have a port
		opts.Addr = envAddr
	} else {
		// TCP case
		opts.Addr = defaults.String(opts.Addr, fmt.Sprintf("%s:%s", envAddr, envy.Get("PORT", "3000")))
	}

	if opts.PreWares == nil {
		opts.PreWares = []PreWare{}
	}
	if opts.PreHandlers == nil {
		opts.PreHandlers = []http.Handler{}
	}

	if opts.Context == nil {
		opts.Context = context.Background()
	}
	opts.Context, opts.cancel = context.WithCancel(opts.Context)

	if opts.Logger == nil {
		opts.Logger = NewLogger(opts.LogLevel)
	}

	pop.Log = func(s string, args ...interface{}) {
		if pop.Debug {
			l := opts.Logger
			if len(args) > 0 {
				for i, a := range args {
					l = l.WithField(fmt.Sprintf("$%d", i+1), a)
				}
			}
			if pop.Color {
				s = color.YellowString(s)
			}
			l.Debug(s)
		}
	}

	if opts.SessionStore == nil {
		secret := envy.Get("SESSION_SECRET", "")
		// In production a SESSION_SECRET must be set!
		if opts.Env == "production" && secret == "" {
			logrus.Warn("Unless you set SESSION_SECRET env variable, your session storage is not protected!")
		}
		opts.SessionStore = sessions.NewCookieStore([]byte(secret))
	}
	if opts.Worker == nil {
		w := worker.NewSimpleWithContext(opts.Context)
		w.Logger = opts.Logger
		opts.Worker = w
	}
	opts.SessionName = defaults.String(opts.SessionName, "_buffalo_session")
	opts.Host = defaults.String(opts.Host, envy.Get("HOST", fmt.Sprintf("http://127.0.0.1:%s", envy.Get("PORT", "3000"))))
	return opts
}
<commit_msg>Support LOG_LEVEL env variable (#1042)<commit_after>package buffalo

import (
	"context"
	"fmt"
	"net/http"
	"strings"

	"github.com/sirupsen/logrus"

	"github.com/fatih/color"
	"github.com/gobuffalo/buffalo/worker"
	"github.com/gobuffalo/envy"
	"github.com/gobuffalo/pop"
	"github.com/gorilla/sessions"
	"github.com/markbates/going/defaults"
)

// Options are used to configure and define how your application should run.
type Options struct {
	Name string
	// Addr is the bind address provided to http.Server. Default is "127.0.0.1:3000"
	// Can be set using ENV vars "ADDR" and "PORT".
	Addr string
	// Host that this application will be available at. Default is "http://127.0.0.1:[$PORT|3000]".
	Host string

	// Env is the "environment" in which the App is running. Default is "development".
	Env string

	// LogLevel defaults to "debug".
	LogLevel string
	// Logger to be used with the application. A default one is provided.
	Logger Logger

	// MethodOverride allows for changing of the request method type. See the default
	// implementation at buffalo.MethodOverride
	MethodOverride http.HandlerFunc

	// SessionStore is the `github.com/gorilla/sessions` store used to back
	// the session. It defaults to use a cookie store and the ENV variable
	// `SESSION_SECRET`.
	SessionStore sessions.Store
	// SessionName is the name of the session cookie that is set. This defaults
	// to "_buffalo_session".
	SessionName string

	// Worker implements the Worker interface and can process tasks in the background.
	// Default is "github.com/gobuffalo/worker.Simple.
	Worker worker.Worker
	// WorkerOff tells App.Start() whether to start the Worker process or not. Default is "false".
	WorkerOff bool

	// PreHandlers are http.Handlers that are called between the http.Server
	// and the buffalo Application.
	PreHandlers []http.Handler
	// PreWare takes an http.Handler and returns and http.Handler
	// and acts as a pseudo-middleware between the http.Server and
	// a Buffalo application.
	PreWares []PreWare

	Context context.Context

	// LooseSlash defines the trailing slash behavior for new routes. The initial value is false.
	// This is the opposite of http://www.gorillatoolkit.org/pkg/mux#Router.StrictSlash
	LooseSlash bool

	cancel context.CancelFunc
	Prefix string
}

// PreWare takes an http.Handler and returns and http.Handler
// and acts as a pseudo-middleware between the http.Server and
// a Buffalo application.
type PreWare func(http.Handler) http.Handler

// NewOptions returns a new Options instance with sensible defaults
func NewOptions() Options {
	return optionsWithDefaults(Options{})
}

func optionsWithDefaults(opts Options) Options {
	opts.Env = defaults.String(opts.Env, envy.Get("GO_ENV", "development"))
	opts.LogLevel = defaults.String(opts.LogLevel, envy.Get("LOG_LEVEL", "debug"))
	opts.Name = defaults.String(opts.Name, "/")
	addr := "0.0.0.0"
	if opts.Env == "development" {
		addr = "127.0.0.1"
	}
	envAddr := envy.Get("ADDR", addr)

	if strings.HasPrefix(envAddr, "unix:") {
		// UNIX domain socket doesn't have a port
		opts.Addr = envAddr
	} else {
		// TCP case
		opts.Addr = defaults.String(opts.Addr, fmt.Sprintf("%s:%s", envAddr, envy.Get("PORT", "3000")))
	}

	if opts.PreWares == nil {
		opts.PreWares = []PreWare{}
	}
	if opts.PreHandlers == nil {
		opts.PreHandlers = []http.Handler{}
	}

	if opts.Context == nil {
		opts.Context = context.Background()
	}
	opts.Context, opts.cancel = context.WithCancel(opts.Context)

	if opts.Logger == nil {
		opts.Logger = NewLogger(opts.LogLevel)
	}

	pop.Log = func(s string, args ...interface{}) {
		if pop.Debug {
			l := opts.Logger
			if len(args) > 0 {
				for i, a := range args {
					l = l.WithField(fmt.Sprintf("$%d", i+1), a)
				}
			}
			if pop.Color {
				s = color.YellowString(s)
			}
			l.Debug(s)
		}
	}

	if opts.SessionStore == nil {
		secret := envy.Get("SESSION_SECRET", "")
		// In production a SESSION_SECRET must be set!
		if opts.Env == "production" && secret == "" {
			logrus.Warn("Unless you set SESSION_SECRET env variable, your session storage is not protected!")
		}
		opts.SessionStore = sessions.NewCookieStore([]byte(secret))
	}
	if opts.Worker == nil {
		w := worker.NewSimpleWithContext(opts.Context)
		w.Logger = opts.Logger
		opts.Worker = w
	}
	opts.SessionName = defaults.String(opts.SessionName, "_buffalo_session")
	opts.Host = defaults.String(opts.Host, envy.Get("HOST", fmt.Sprintf("http://127.0.0.1:%s", envy.Get("PORT", "3000"))))
	return opts
}
<|endoftext|>


<commit_before>package leveldb

import (
	"unsafe"

	"github.com/kezhuw/leveldb/internal/compaction"
	"github.com/kezhuw/leveldb/internal/compress"
	"github.com/kezhuw/leveldb/internal/file"
	"github.com/kezhuw/leveldb/internal/filter"
	"github.com/kezhuw/leveldb/internal/keys"
	"github.com/kezhuw/leveldb/internal/logger"
	"github.com/kezhuw/leveldb/internal/options"
)

const (
	// MaxCompactionConcurrency maximize compaction concurrency as possible.
	// Caution that compaction is a disk drive sensitive task, max compaction
	// concurrency usually doesn't mean good performance.
	MaxCompactionConcurrency = compaction.MaxCompactionConcurrency
)

// CompressionType defines compression methods to compress a table block.
type CompressionType int

const (
	// DefaultCompression defaults to SnappyCompression for now.
	DefaultCompression CompressionType = iota
	// NoCompression means no compression for table block.
	NoCompression
	// SnappyCompression uses snappy compression to compress table block
	// before store it to file.
	SnappyCompression
)

// Options contains options controlling various parts of the db instance.
type Options struct {
	// Comparator defines the total order over keys in the database.
	//
	// The default comparator is BytewiseComparator, which uses the same ordering
	// as bytes.Compare.
	Comparator Comparator

	// Compression type used to compress blocks.
	//
	// The default value points to SnappyCompression.
	Compression CompressionType

	// BlockSize specifys the minimum uncompressed size in bytes for a table block.
	//
	// The default value is 4KiB.
	BlockSize int

	// BlockRestartInterval specifys the number of keys between restart points
	// for delta encoding of keys in a block.
	//
	// The default value is 16.
	BlockRestartInterval int

	// BlockCompressionRatio specifies a minimal compression ratio for table blocks.
	// Uncompressed block will be written to table file if its compression ratio is
	// this value.
	//
	// The default value is 8.0/7.0, which means that uncompressed block will be written
	// to table file unless at least 1/8 of raw data were compressed out.
	BlockCompressionRatio float64

	// WriteBufferSize is the amount of data to build up in memory (backed by
	// an unsorted log on disk) before converting to a sorted on-disk file.
	//
	// Larger values increase performance, especially during bulk loads. Up to two
	// write buffers may be held in memory at the same time, so you may wish to
	// adjust this parameter to control memory usage. Also, a larger write buffer
	// will result in a longer recovery time the next time the database is opened.
	//
	// The default value is 4MiB.
	WriteBufferSize int

	// MaxOpenFiles is the number of open files that can be used this db instance.
	// You may need to increase this if your database has a large number of files.
	//
	// The default value is 1000.
	MaxOpenFiles int

	// BlockCacheCapacity specifys the capacity in bytes for block cache.
	//
	// The default value is 8MiB.
	BlockCacheCapacity int

	// CompactionConcurrency specifies max allowed concurrent compactions.
	//
	// The default value is 1, use MaxCompactionConcurrency to maximize compaction
	// concurrency as poosible.
	CompactionConcurrency int

	// CompactionBytesPerSeek states that one seek cost approximately equal time
	// to compact specified number of data.
	//
	// We decide to compact a file after a certain number of overlap seeks, this
	// way for keys in range we reduce potential seeks by one after compaction.
	// We use CompactionBytesPerSeek and MinimalAllowedOverlapSeeks to calculate
	// the number of allowed overlap seeks for a file.
	//
	// The default value is 16KiB, which means that one seek cost approximately
	// equal time to compact 16KiB data.
	CompactionBytesPerSeek int

	// MinimalAllowedOverlapSeeks specifies minimal allowed overlap seeks per table file.
	//
	// The default value is 100.
	MinimalAllowedOverlapSeeks int

	// IterationBytesPerSampleSeek specifies average iteration bytes for one sample
	// seek to detect overlap file.
	//
	// The default value is 1MiB.
	IterationBytesPerSampleSeek int

	// Level0CompactionFiles specifies that a compaction for level-0 is triggered if
	// there are more than this number of files in level-0.
	//
	// The default value is 4.
	Level0CompactionFiles int

	// Level0SlowdownWriteFiles specifies that writes will be slowdown if there are
	// more than this number of files in level-0.
	//
	// The default value is Level0CompactionFiles + 4.
	Level0SlowdownWriteFiles int

	// Level0StopWriteFiles specifies that writes will be stopped if there are more
	// than this number of files in level-0.
	//
	// The default value is Level0SlowdownWriteFiles + 4.
	Level0StopWriteFiles int

	// Filter specifys a Filter to filter out unnecessary disk reads when looking for
	// a specific key. The filter is also used to generate filter data when building
	// table files.
	//
	// The default value is nil.
	Filter Filter

	// Logger specifys a place that all internal progress/error information generated
	// by this db instance will be written to.
	//
	// The default value is a file named "LOG" stored under this db directory. You can
	// suppress logging by using DiscardLogger.
	Logger Logger

	// FileSystem defines a hierarchical file storage interface.
	//
	// The default file system is built around os package.
	FileSystem FileSystem

	// CreateIfMissing specifys whether to create one if the database does not exist.
	//
	// The default value is false.
	CreateIfMissing bool

	// ErrorIfExists specifys whether to report a error if the database already exists.
	//
	// The default value is false.
	ErrorIfExists bool
}

func (opts *Options) getLogger() logger.LogCloser {
	if opts.Logger == nil {
		return nil
	}
	return logger.NopCloser(opts.Logger)
}

func (opts *Options) getFilter() filter.Filter {
	if opts.Filter == nil {
		return nil
	}
	if f, ok := opts.Filter.(internalFilter); ok {
		return f.Filter
	}
	return wrappedFilter{opts.Filter}
}

func (opts *Options) getFileSystem() file.FileSystem {
	if opts.FileSystem == nil {
		return file.DefaultFileSystem
	}
	if fs, ok := opts.FileSystem.(internalFileSystem); ok {
		return fs.FileSystem
	}
	return wrappedFileSystem{opts.FileSystem}
}

func (opts *Options) getComparator() *keys.InternalComparator {
	if opts.Comparator == nil || opts.Comparator == keys.BytewiseComparator {
		return &options.DefaultInternalComparator
	}
	return &keys.InternalComparator{UserKeyComparator: opts.Comparator}
}

func (opts *Options) getCompression() compress.Type {
	switch opts.Compression {
	case NoCompression:
		return compress.NoCompression
	case SnappyCompression:
		return compress.SnappyCompression
	}
	return options.DefaultCompression
}

func (opts *Options) getBlockSize() int {
	if opts.BlockSize <= 0 {
		return options.DefaultBlockSize
	}
	return opts.BlockSize
}

func (opts *Options) getBlockRestartInterval() int {
	if opts.BlockRestartInterval <= 0 {
		return options.DefaultBlockRestartInterval
	}
	return opts.BlockRestartInterval
}

func (opts *Options) getBlockCompressionRatio() float64 {
	if opts.BlockCompressionRatio <= 1 {
		return options.DefaultBlockCompressionRatio
	}
	return opts.BlockCompressionRatio
}

func (opts *Options) getWriteBufferSize() int {
	if opts.WriteBufferSize <= 0 {
		return options.DefaultWriteBufferSize
	}
	return opts.WriteBufferSize
}

func (opts *Options) getMaxOpenFiles() int {
	if opts.MaxOpenFiles <= 0 {
		return options.DefaultMaxOpenFiles
	}
	return opts.MaxOpenFiles
}

func (opts *Options) getBlockCacheCapacity() int {
	if opts.BlockCacheCapacity <= 0 {
		return options.DefaultBlockCacheCapacity
	}
	return opts.BlockCacheCapacity
}

func (opts *Options) getCompactionConcurrency() int {
	switch {
	case opts.CompactionConcurrency == 0:
		return options.DefaultCompactionConcurrency
	case opts.CompactionConcurrency < 0:
		return compaction.MaxCompactionConcurrency
	default:
		return opts.CompactionConcurrency
	}
}

func (opts *Options) getCompactionBytesPerSeek() int {
	if opts.CompactionBytesPerSeek <= 0 {
		return options.DefaultCompactionBytesPerSeek
	}
	return opts.CompactionBytesPerSeek
}

func (opts *Options) getMinimalAllowedOverlapSeeks() int {
	if opts.MinimalAllowedOverlapSeeks <= 0 {
		return options.DefaultMinimalAllowedOverlapSeeks
	}
	return opts.MinimalAllowedOverlapSeeks
}

func (opts *Options) getIterationBytesPerSampleSeek() int {
	if opts.IterationBytesPerSampleSeek <= 0 {
		return options.DefaultIterationBytesPerSampleSeek
	}
	return opts.IterationBytesPerSampleSeek
}

func (opts *Options) getLevel0CompactionFiles() int {
	if opts.Level0CompactionFiles <= 0 {
		return options.DefaultLevel0CompactionFiles
	}
	return opts.Level0CompactionFiles
}

func (opts *Options) getLevel0SlowdownWriteFiles() int {
	if opts.Level0SlowdownWriteFiles <= opts.getLevel0CompactionFiles() {
		return opts.getLevel0CompactionFiles() + options.DefaultLevel0ThrottleStepFiles
	}
	return opts.Level0SlowdownWriteFiles
}

func (opts *Options) getLevel0StopWriteFiles() int {
	if opts.Level0StopWriteFiles <= opts.getLevel0SlowdownWriteFiles() {
		return opts.getLevel0SlowdownWriteFiles() + options.DefaultLevel0ThrottleStepFiles
	}
	return opts.Level0StopWriteFiles
}

func convertOptions(opts *Options) *options.Options {
	if opts == nil {
		return &options.DefaultOptions
	}
	var iopts options.Options
	iopts.Comparator = opts.getComparator()
	iopts.Compression = opts.getCompression()
	iopts.BlockSize = opts.getBlockSize()
	iopts.BlockRestartInterval = opts.getBlockRestartInterval()
	iopts.BlockCompressionRatio = opts.getBlockCompressionRatio()
	iopts.WriteBufferSize = opts.getWriteBufferSize()
	iopts.MaxOpenFiles = opts.getMaxOpenFiles()
	iopts.BlockCacheCapacity = opts.getBlockCacheCapacity()
	iopts.CompactionConcurrency = opts.getCompactionConcurrency()
	iopts.CompactionBytesPerSeek = opts.getCompactionBytesPerSeek()
	iopts.MinimalAllowedOverlapSeeks = opts.getMinimalAllowedOverlapSeeks()
	iopts.IterationBytesPerSampleSeek = opts.getIterationBytesPerSampleSeek()
	iopts.Level0CompactionFiles = opts.getLevel0CompactionFiles()
	iopts.Level0SlowdownWriteFiles = opts.getLevel0SlowdownWriteFiles()
	iopts.Level0StopWriteFiles = opts.getLevel0StopWriteFiles()
	iopts.Filter = opts.getFilter()
	iopts.Logger = opts.getLogger()
	iopts.FileSystem = opts.getFileSystem()
	iopts.CreateIfMissing = opts.CreateIfMissing
	iopts.ErrorIfExists = opts.ErrorIfExists
	return &iopts
}

// ReadOptions contains options controlling behaviours of read operations.
type ReadOptions struct {
	// DontFillCache specifys whether data read in this operation
	// should be cached in memory. If true, data read from underlying
	// storage will not be cahced in memory for later reading, but
	// if the data is already cached in memory, it will be used by
	// this operation.
	DontFillCache bool

	// VerifyChecksums specifys whether data read from underlying
	// storage should be verified against saved checksums. Note that
	// it never verify data cached in memory.
	VerifyChecksums bool
}

func convertReadOptions(opts *ReadOptions) *options.ReadOptions {
	if opts == nil {
		return &options.DefaultReadOptions
	}
	return (*options.ReadOptions)(unsafe.Pointer(opts))
}

// WriteOptions contains options controlling write operations: Put, Delete,
// and Write.
type WriteOptions struct {
	// Sync specifys whether to synchronize the write from OS cache to
	// underlying storage before the write is considered complete.
	// Setting Sync to true may result in slower writes.
	//
	// If Sync is false, and the machine crashs, some recent writes may
	// be lost. Note that if it is just the process crashs, no writes will
	// be lost.
	//
	// In other words, a write with false Sync has similar crash semantics
	// as the "write()" system call. A write with true Sync has similar crash
	/// semantics to a "write()" system call followed by "fsync()".
	Sync bool
}

func convertWriteOptions(opts *WriteOptions) *options.WriteOptions {
	if opts == nil {
		return &options.DefaultWriteOptions
	}
	return (*options.WriteOptions)(unsafe.Pointer(opts))
}
<commit_msg>Fix typo<commit_after>package leveldb

import (
	"unsafe"

	"github.com/kezhuw/leveldb/internal/compaction"
	"github.com/kezhuw/leveldb/internal/compress"
	"github.com/kezhuw/leveldb/internal/file"
	"github.com/kezhuw/leveldb/internal/filter"
	"github.com/kezhuw/leveldb/internal/keys"
	"github.com/kezhuw/leveldb/internal/logger"
	"github.com/kezhuw/leveldb/internal/options"
)

const (
	// MaxCompactionConcurrency maximize compaction concurrency as possible.
	// Caution that compaction is a disk drive sensitive task, max compaction
	// concurrency usually doesn't mean good performance.
	MaxCompactionConcurrency = compaction.MaxCompactionConcurrency
)

// CompressionType defines compression methods to compress a table block.
type CompressionType int

const (
	// DefaultCompression defaults to SnappyCompression for now.
	DefaultCompression CompressionType = iota
	// NoCompression means no compression for table block.
	NoCompression
	// SnappyCompression uses snappy compression to compress table block
	// before store it to file.
	SnappyCompression
)

// Options contains options controlling various parts of the db instance.
type Options struct {
	// Comparator defines the total order over keys in the database.
	//
	// The default comparator is BytewiseComparator, which uses the same ordering
	// as bytes.Compare.
	Comparator Comparator

	// Compression type used to compress blocks.
	//
	// The default value points to SnappyCompression.
	Compression CompressionType

	// BlockSize specifies the minimum uncompressed size in bytes for a table block.
	//
	// The default value is 4KiB.
	BlockSize int

	// BlockRestartInterval specifies the number of keys between restart points
	// for delta encoding of keys in a block.
	//
	// The default value is 16.
	BlockRestartInterval int

	// BlockCompressionRatio specifies a minimal compression ratio for table blocks.
	// Uncompressed block will be written to table file if its compression ratio is
	// this value.
	//
	// The default value is 8.0/7.0, which means that uncompressed block will be written
	// to table file unless at least 1/8 of raw data were compressed out.
	BlockCompressionRatio float64

	// WriteBufferSize is the amount of data to build up in memory (backed by
	// an unsorted log on disk) before converting to a sorted on-disk file.
	//
	// Larger values increase performance, especially during bulk loads. Up to two
	// write buffers may be held in memory at the same time, so you may wish to
	// adjust this parameter to control memory usage. Also, a larger write buffer
	// will result in a longer recovery time the next time the database is opened.
	//
	// The default value is 4MiB.
	WriteBufferSize int

	// MaxOpenFiles is the number of open files that can be used this db instance.
	// You may need to increase this if your database has a large number of files.
	//
	// The default value is 1000.
	MaxOpenFiles int

	// BlockCacheCapacity specifies the capacity in bytes for block cache.
	//
	// The default value is 8MiB.
	BlockCacheCapacity int

	// CompactionConcurrency specifies max allowed concurrent compactions.
	//
	// The default value is 1, use MaxCompactionConcurrency to maximize compaction
	// concurrency as poosible.
	CompactionConcurrency int

	// CompactionBytesPerSeek states that one seek cost approximately equal time
	// to compact specified number of data.
	//
	// We decide to compact a file after a certain number of overlap seeks, this
	// way for keys in range we reduce potential seeks by one after compaction.
	// We use CompactionBytesPerSeek and MinimalAllowedOverlapSeeks to calculate
	// the number of allowed overlap seeks for a file.
	//
	// The default value is 16KiB, which means that one seek cost approximately
	// equal time to compact 16KiB data.
	CompactionBytesPerSeek int

	// MinimalAllowedOverlapSeeks specifies minimal allowed overlap seeks per table file.
	//
	// The default value is 100.
	MinimalAllowedOverlapSeeks int

	// IterationBytesPerSampleSeek specifies average iteration bytes for one sample
	// seek to detect overlap file.
	//
	// The default value is 1MiB.
	IterationBytesPerSampleSeek int

	// Level0CompactionFiles specifies that a compaction for level-0 is triggered if
	// there are more than this number of files in level-0.
	//
	// The default value is 4.
	Level0CompactionFiles int

	// Level0SlowdownWriteFiles specifies that writes will be slowdown if there are
	// more than this number of files in level-0.
	//
	// The default value is Level0CompactionFiles + 4.
	Level0SlowdownWriteFiles int

	// Level0StopWriteFiles specifies that writes will be stopped if there are more
	// than this number of files in level-0.
	//
	// The default value is Level0SlowdownWriteFiles + 4.
	Level0StopWriteFiles int

	// Filter specifies a Filter to filter out unnecessary disk reads when looking for
	// a specific key. The filter is also used to generate filter data when building
	// table files.
	//
	// The default value is nil.
	Filter Filter

	// Logger specifies a place that all internal progress/error information generated
	// by this db instance will be written to.
	//
	// The default value is a file named "LOG" stored under this db directory. You can
	// suppress logging by using DiscardLogger.
	Logger Logger

	// FileSystem defines a hierarchical file storage interface.
	//
	// The default file system is built around os package.
	FileSystem FileSystem

	// CreateIfMissing specifies whether to create one if the database does not exist.
	//
	// The default value is false.
	CreateIfMissing bool

	// ErrorIfExists specifies whether to report a error if the database already exists.
	//
	// The default value is false.
	ErrorIfExists bool
}

func (opts *Options) getLogger() logger.LogCloser {
	if opts.Logger == nil {
		return nil
	}
	return logger.NopCloser(opts.Logger)
}

func (opts *Options) getFilter() filter.Filter {
	if opts.Filter == nil {
		return nil
	}
	if f, ok := opts.Filter.(internalFilter); ok {
		return f.Filter
	}
	return wrappedFilter{opts.Filter}
}

func (opts *Options) getFileSystem() file.FileSystem {
	if opts.FileSystem == nil {
		return file.DefaultFileSystem
	}
	if fs, ok := opts.FileSystem.(internalFileSystem); ok {
		return fs.FileSystem
	}
	return wrappedFileSystem{opts.FileSystem}
}

func (opts *Options) getComparator() *keys.InternalComparator {
	if opts.Comparator == nil || opts.Comparator == keys.BytewiseComparator {
		return &options.DefaultInternalComparator
	}
	return &keys.InternalComparator{UserKeyComparator: opts.Comparator}
}

func (opts *Options) getCompression() compress.Type {
	switch opts.Compression {
	case NoCompression:
		return compress.NoCompression
	case SnappyCompression:
		return compress.SnappyCompression
	}
	return options.DefaultCompression
}

func (opts *Options) getBlockSize() int {
	if opts.BlockSize <= 0 {
		return options.DefaultBlockSize
	}
	return opts.BlockSize
}

func (opts *Options) getBlockRestartInterval() int {
	if opts.BlockRestartInterval <= 0 {
		return options.DefaultBlockRestartInterval
	}
	return opts.BlockRestartInterval
}

func (opts *Options) getBlockCompressionRatio() float64 {
	if opts.BlockCompressionRatio <= 1 {
		return options.DefaultBlockCompressionRatio
	}
	return opts.BlockCompressionRatio
}

func (opts *Options) getWriteBufferSize() int {
	if opts.WriteBufferSize <= 0 {
		return options.DefaultWriteBufferSize
	}
	return opts.WriteBufferSize
}

func (opts *Options) getMaxOpenFiles() int {
	if opts.MaxOpenFiles <= 0 {
		return options.DefaultMaxOpenFiles
	}
	return opts.MaxOpenFiles
}

func (opts *Options) getBlockCacheCapacity() int {
	if opts.BlockCacheCapacity <= 0 {
		return options.DefaultBlockCacheCapacity
	}
	return opts.BlockCacheCapacity
}

func (opts *Options) getCompactionConcurrency() int {
	switch {
	case opts.CompactionConcurrency == 0:
		return options.DefaultCompactionConcurrency
	case opts.CompactionConcurrency < 0:
		return compaction.MaxCompactionConcurrency
	default:
		return opts.CompactionConcurrency
	}
}

func (opts *Options) getCompactionBytesPerSeek() int {
	if opts.CompactionBytesPerSeek <= 0 {
		return options.DefaultCompactionBytesPerSeek
	}
	return opts.CompactionBytesPerSeek
}

func (opts *Options) getMinimalAllowedOverlapSeeks() int {
	if opts.MinimalAllowedOverlapSeeks <= 0 {
		return options.DefaultMinimalAllowedOverlapSeeks
	}
	return opts.MinimalAllowedOverlapSeeks
}

func (opts *Options) getIterationBytesPerSampleSeek() int {
	if opts.IterationBytesPerSampleSeek <= 0 {
		return options.DefaultIterationBytesPerSampleSeek
	}
	return opts.IterationBytesPerSampleSeek
}

func (opts *Options) getLevel0CompactionFiles() int {
	if opts.Level0CompactionFiles <= 0 {
		return options.DefaultLevel0CompactionFiles
	}
	return opts.Level0CompactionFiles
}

func (opts *Options) getLevel0SlowdownWriteFiles() int {
	if opts.Level0SlowdownWriteFiles <= opts.getLevel0CompactionFiles() {
		return opts.getLevel0CompactionFiles() + options.DefaultLevel0ThrottleStepFiles
	}
	return opts.Level0SlowdownWriteFiles
}

func (opts *Options) getLevel0StopWriteFiles() int {
	if opts.Level0StopWriteFiles <= opts.getLevel0SlowdownWriteFiles() {
		return opts.getLevel0SlowdownWriteFiles() + options.DefaultLevel0ThrottleStepFiles
	}
	return opts.Level0StopWriteFiles
}

func convertOptions(opts *Options) *options.Options {
	if opts == nil {
		return &options.DefaultOptions
	}
	var iopts options.Options
	iopts.Comparator = opts.getComparator()
	iopts.Compression = opts.getCompression()
	iopts.BlockSize = opts.getBlockSize()
	iopts.BlockRestartInterval = opts.getBlockRestartInterval()
	iopts.BlockCompressionRatio = opts.getBlockCompressionRatio()
	iopts.WriteBufferSize = opts.getWriteBufferSize()
	iopts.MaxOpenFiles = opts.getMaxOpenFiles()
	iopts.BlockCacheCapacity = opts.getBlockCacheCapacity()
	iopts.CompactionConcurrency = opts.getCompactionConcurrency()
	iopts.CompactionBytesPerSeek = opts.getCompactionBytesPerSeek()
	iopts.MinimalAllowedOverlapSeeks = opts.getMinimalAllowedOverlapSeeks()
	iopts.IterationBytesPerSampleSeek = opts.getIterationBytesPerSampleSeek()
	iopts.Level0CompactionFiles = opts.getLevel0CompactionFiles()
	iopts.Level0SlowdownWriteFiles = opts.getLevel0SlowdownWriteFiles()
	iopts.Level0StopWriteFiles = opts.getLevel0StopWriteFiles()
	iopts.Filter = opts.getFilter()
	iopts.Logger = opts.getLogger()
	iopts.FileSystem = opts.getFileSystem()
	iopts.CreateIfMissing = opts.CreateIfMissing
	iopts.ErrorIfExists = opts.ErrorIfExists
	return &iopts
}

// ReadOptions contains options controlling behaviours of read operations.
type ReadOptions struct {
	// DontFillCache specifies whether data read in this operation
	// should be cached in memory. If true, data read from underlying
	// storage will not be cahced in memory for later reading, but
	// if the data is already cached in memory, it will be used by
	// this operation.
	DontFillCache bool

	// VerifyChecksums specifies whether data read from underlying
	// storage should be verified against saved checksums. Note that
	// it never verify data cached in memory.
	VerifyChecksums bool
}

func convertReadOptions(opts *ReadOptions) *options.ReadOptions {
	if opts == nil {
		return &options.DefaultReadOptions
	}
	return (*options.ReadOptions)(unsafe.Pointer(opts))
}

// WriteOptions contains options controlling write operations: Put, Delete,
// and Write.
type WriteOptions struct {
	// Sync specifies whether to synchronize the write from OS cache to
	// underlying storage before the write is considered complete.
	// Setting Sync to true may result in slower writes.
	//
	// If Sync is false, and the machine crashs, some recent writes may
	// be lost. Note that if it is just the process crashs, no writes will
	// be lost.
	//
	// In other words, a write with false Sync has similar crash semantics
	// as the "write()" system call. A write with true Sync has similar crash
	// semantics to a "write()" system call followed by "fsync()".
	Sync bool
}

func convertWriteOptions(opts *WriteOptions) *options.WriteOptions {
	if opts == nil {
		return &options.DefaultWriteOptions
	}
	return (*options.WriteOptions)(unsafe.Pointer(opts))
}
<|endoftext|>


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

package validate

import (
	"errors"
	"reflect"
	"testing"

	// Import into the same namespace to keep config definitions clean
	. "github.com/coreos/ignition/config/types"
	"github.com/coreos/ignition/config/validate/report"
)

func TestValidate(t *testing.T) {
	type in struct {
		cfg Config
	}
	type out struct {
		err error
	}

	tests := []struct {
		in  in
		out out
	}{
		{
			in:  in{cfg: Config{Ignition: Ignition{Version: IgnitionVersion{Major: 2}}}},
			out: out{},
		},
		{
			in:  in{cfg: Config{}},
			out: out{err: ErrOldVersion},
		},
		{
			in: in{cfg: Config{
				Ignition: Ignition{
					Version: IgnitionVersion{Major: 2},
					Config: IgnitionConfig{
						Replace: &ConfigReference{
							Verification: Verification{
								Hash: &Hash{Function: "foobar"},
							},
						},
					},
				},
			}},
			out: out{errors.New("unrecognized hash function")},
		},
		{
			in: in{cfg: Config{
				Ignition: Ignition{Version: IgnitionVersion{Major: 2}},
				Storage: Storage{
					Filesystems: []Filesystem{
						{
							Name: "filesystem1",
							Mount: &FilesystemMount{
								Device: Path("/dev/disk/by-partlabel/ROOT"),
								Format: FilesystemFormat("btrfs"),
							},
						},
					},
				},
			}},
			out: out{},
		},
		{
			in: in{cfg: Config{
				Ignition: Ignition{Version: IgnitionVersion{Major: 2}},
				Storage: Storage{
					Filesystems: []Filesystem{
						{
							Name: "filesystem1",
							Path: func(p Path) *Path { return &p }("/sysroot"),
						},
					},
				},
			}},
			out: out{},
		},
		{
			in: in{cfg: Config{
				Ignition: Ignition{Version: IgnitionVersion{Major: 2}},
				Systemd:  Systemd{Units: []SystemdUnit{{Name: "foo.bar", Contents: "[Foo]\nfoo=qux"}}},
			}},
			out: out{err: errors.New("invalid systemd unit extension")},
		},
	}

	for i, test := range tests {
		r := ValidateWithoutSource(reflect.ValueOf(test.in.cfg))
		expectedReport := report.ReportFromError(test.out.err, report.EntryError)
		if !reflect.DeepEqual(expectedReport, r) {
			t.Errorf("#%d: bad error: want %v, got %v", i, expectedReport, r)
		}
	}
}
<commit_msg>tests: add test for getfields()<commit_after>// Copyright 2016 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package validate

import (
	"errors"
	"reflect"
	"testing"

	// Import into the same namespace to keep config definitions clean
	. "github.com/coreos/ignition/config/types"
	"github.com/coreos/ignition/config/validate/report"
)

func TestValidate(t *testing.T) {
	type in struct {
		cfg Config
	}
	type out struct {
		err error
	}

	tests := []struct {
		in  in
		out out
	}{
		{
			in:  in{cfg: Config{Ignition: Ignition{Version: IgnitionVersion{Major: 2}}}},
			out: out{},
		},
		{
			in:  in{cfg: Config{}},
			out: out{err: ErrOldVersion},
		},
		{
			in: in{cfg: Config{
				Ignition: Ignition{
					Version: IgnitionVersion{Major: 2},
					Config: IgnitionConfig{
						Replace: &ConfigReference{
							Verification: Verification{
								Hash: &Hash{Function: "foobar"},
							},
						},
					},
				},
			}},
			out: out{errors.New("unrecognized hash function")},
		},
		{
			in: in{cfg: Config{
				Ignition: Ignition{Version: IgnitionVersion{Major: 2}},
				Storage: Storage{
					Filesystems: []Filesystem{
						{
							Name: "filesystem1",
							Mount: &FilesystemMount{
								Device: Path("/dev/disk/by-partlabel/ROOT"),
								Format: FilesystemFormat("btrfs"),
							},
						},
					},
				},
			}},
			out: out{},
		},
		{
			in: in{cfg: Config{
				Ignition: Ignition{Version: IgnitionVersion{Major: 2}},
				Storage: Storage{
					Filesystems: []Filesystem{
						{
							Name: "filesystem1",
							Path: func(p Path) *Path { return &p }("/sysroot"),
						},
					},
				},
			}},
			out: out{},
		},
		{
			in: in{cfg: Config{
				Ignition: Ignition{Version: IgnitionVersion{Major: 2}},
				Systemd:  Systemd{Units: []SystemdUnit{{Name: "foo.bar", Contents: "[Foo]\nfoo=qux"}}},
			}},
			out: out{err: errors.New("invalid systemd unit extension")},
		},
	}

	for i, test := range tests {
		r := ValidateWithoutSource(reflect.ValueOf(test.in.cfg))
		expectedReport := report.ReportFromError(test.out.err, report.EntryError)
		if !reflect.DeepEqual(expectedReport, r) {
			t.Errorf("#%d: bad error: want %v, got %v", i, expectedReport, r)
		}
	}
}

func TestGetFields(t *testing.T) {
	// basic case
	type Test1 struct {
		A int
		B string
	}
	test1 := Test1{
		A: 1,
		B: "one",
	}

	// test embedded structs
	type Test2 struct {
		C int
		Test1
	}
	test2 := Test2{
		C:     5,
		Test1: test1,
	}

	// test doublely embedded structs
	type Test3 struct {
		D int
		Test2
	}
	test3 := Test3{
		D:     3,
		Test2: test2,
	}
	// test structs embedded via an alias to interface{}
	type Anything interface{}

	test4 := struct {
		E int
		Anything
	}{
		E:        7,
		Anything: test3,
	}

	// test normally contained structs don't cause problems
	test5 := struct {
		E int
		F Test3
	}{
		E: 2,
		F: test3,
	}

	// test non-structs embedded via an alias to interface{} don't cause panics
	test6 := struct {
		E int
		Anything
	}{
		E:        5,
		Anything: 65,
	}

	// test embedded nils
	test7 := struct {
		E int
		Anything
	}{
		E: 5,
	}

	type in struct {
		strct reflect.Value
	}
	type out struct {
		fields []field
	}

	tests := []struct {
		in  in
		out out
	}{
		{
			in: in{strct: reflect.ValueOf(test1)},
			out: out{fields: []field{
				{
					Type:  reflect.TypeOf(test1).Field(0),
					Value: reflect.ValueOf(test1.A),
				},
				{
					Type:  reflect.TypeOf(test1).Field(1),
					Value: reflect.ValueOf(test1.B),
				},
			}},
		},
		{
			in: in{strct: reflect.ValueOf(test2)},
			out: out{fields: []field{
				{
					Type:  reflect.TypeOf(test2).Field(0),
					Value: reflect.ValueOf(test2.C),
				},
				{
					Type:  reflect.TypeOf(test1).Field(0),
					Value: reflect.ValueOf(test1.A),
				},
				{
					Type:  reflect.TypeOf(test1).Field(1),
					Value: reflect.ValueOf(test1.B),
				},
			}},
		},
		{
			in: in{strct: reflect.ValueOf(test3)},
			out: out{fields: []field{
				{
					Type:  reflect.TypeOf(test3).Field(0),
					Value: reflect.ValueOf(test3.D),
				},
				{
					Type:  reflect.TypeOf(test2).Field(0),
					Value: reflect.ValueOf(test2.C),
				},
				{
					Type:  reflect.TypeOf(test1).Field(0),
					Value: reflect.ValueOf(test1.A),
				},
				{
					Type:  reflect.TypeOf(test1).Field(1),
					Value: reflect.ValueOf(test1.B),
				},
			}},
		},
		{
			in: in{strct: reflect.ValueOf(test4)},
			out: out{fields: []field{
				{
					Type:  reflect.TypeOf(test4).Field(0),
					Value: reflect.ValueOf(test4.E),
				},
				{
					Type:  reflect.TypeOf(test3).Field(0),
					Value: reflect.ValueOf(test3.D),
				},
				{
					Type:  reflect.TypeOf(test2).Field(0),
					Value: reflect.ValueOf(test2.C),
				},
				{
					Type:  reflect.TypeOf(test1).Field(0),
					Value: reflect.ValueOf(test1.A),
				},
				{
					Type:  reflect.TypeOf(test1).Field(1),
					Value: reflect.ValueOf(test1.B),
				},
			}},
		},
		{
			in: in{strct: reflect.ValueOf(test5)},
			out: out{fields: []field{
				{
					Type:  reflect.TypeOf(test5).Field(0),
					Value: reflect.ValueOf(test5.E),
				},
				{
					Type:  reflect.TypeOf(test5).Field(1),
					Value: reflect.ValueOf(test5.F),
				},
			}},
		},
		{
			in: in{strct: reflect.ValueOf(test6)},
			out: out{fields: []field{
				{
					Type:  reflect.TypeOf(test6).Field(0),
					Value: reflect.ValueOf(test6.E),
				},
				{
					Type:  reflect.TypeOf(test6).Field(1),
					Value: reflect.ValueOf(65),
				},
			}},
		},
		{
			in: in{strct: reflect.ValueOf(test7)},
			out: out{fields: []field{
				{
					Type:  reflect.TypeOf(test7).Field(0),
					Value: reflect.ValueOf(test7.E),
				},
				{
					Type:  reflect.TypeOf(test7).Field(1),
					Value: reflect.ValueOf(nil),
				},
			}},
		},
	}

	for i, test := range tests {
		fields := getFields(test.in.strct)
		// We cannot use reflect.DeepEqual because reflect.DeepEqual(reflect.ValueOf(someinstance),reflect.ValueOf(someinstance))
		// will always return false. We must manually loop over it and convert reflect.Value's to interface{}'s as we go
		for idx, f := range fields {
			if !reflect.DeepEqual(f.Type, test.out.fields[idx].Type) {
				t.Errorf("#%d: bad error with type: want \n%+v, got \n%+v", i, fields, test.out.fields)
			}
			if !reflect.DeepEqual(f.Value.Interface(), test.out.fields[idx].Value.Interface()) {
				t.Errorf("#%d: bad error: want \n%+v, got \n%+v", i, fields, test.out.fields)
			}
		}
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package restclient

import (
	"math"
	"net/url"
	"time"

	"k8s.io/client-go/tools/metrics"
	k8smetrics "k8s.io/component-base/metrics"
	"k8s.io/component-base/metrics/legacyregistry"
)

var (
	// requestLatency is a Prometheus Summary metric type partitioned by
	// "verb" and "url" labels. It is used for the rest client latency metrics.
	requestLatency = k8smetrics.NewHistogramVec(
		&k8smetrics.HistogramOpts{
			Name:    "rest_client_request_duration_seconds",
			Help:    "Request latency in seconds. Broken down by verb and URL.",
			Buckets: k8smetrics.ExponentialBuckets(0.001, 2, 10),
		},
		[]string{"verb", "url"},
	)

	// deprecatedRequestLatency is deprecated, please use requestLatency.
	deprecatedRequestLatency = k8smetrics.NewHistogramVec(
		&k8smetrics.HistogramOpts{
			Name:              "rest_client_request_latency_seconds",
			Help:              "Request latency in seconds. Broken down by verb and URL.",
			Buckets:           k8smetrics.ExponentialBuckets(0.001, 2, 10),
			DeprecatedVersion: "1.14.0",
		},
		[]string{"verb", "url"},
	)

	requestResult = k8smetrics.NewCounterVec(
		&k8smetrics.CounterOpts{
			Name: "rest_client_requests_total",
			Help: "Number of HTTP requests, partitioned by status code, method, and host.",
		},
		[]string{"code", "method", "host"},
	)

	execPluginCertTTL = k8smetrics.NewGauge(
		&k8smetrics.GaugeOpts{
			Name: "rest_client_exec_plugin_ttl_seconds",
			Help: "Gauge of the shortest TTL (time-to-live) of the client " +
				"certificate(s) managed by the auth exec plugin. The value " +
				"is in seconds until certificate expiry. If auth exec " +
				"plugins are unused or manage no TLS certificates, the " +
				"value will be +INF.",
		},
	)

	execPluginCertRotation = k8smetrics.NewHistogram(
		&k8smetrics.HistogramOpts{
			Name: "rest_client_exec_plugin_certificate_rotation_age",
			Help: "Histogram of the number of seconds the last auth exec " +
				"plugin client certificate lived before being rotated. " +
				"If auth exec plugin client certificates are unused, " +
				"histogram will contain no data.",
			// There are three sets of ranges these buckets intend to capture:
			//   - 10-60 minutes: captures a rotation cadence which is
			//     happening too quickly.
			//   - 4 hours - 1 month: captures an ideal rotation cadence.
			//   - 3 months - 4 years: captures a rotation cadence which is
			//     is probably too slow or much too slow.
			Buckets: []float64{
				600,       // 10 minutes
				1800,      // 30 minutes
				3600,      // 1  hour
				14400,     // 4  hours
				86400,     // 1  day
				604800,    // 1  week
				2592000,   // 1  month
				7776000,   // 3  months
				15552000,  // 6  months
				31104000,  // 1  year
				124416000, // 4  years
			},
		},
	)
)

func init() {
	execPluginCertTTL.Set(math.Inf(1)) // Initialize TTL to +INF

	legacyregistry.MustRegister(requestLatency)
	legacyregistry.MustRegister(deprecatedRequestLatency)
	legacyregistry.MustRegister(requestResult)
	legacyregistry.MustRegister(execPluginCertTTL)
	legacyregistry.MustRegister(execPluginCertRotation)
	metrics.Register(metrics.RegisterOpts{
		ClientCertTTL:         &ttlAdapter{m: execPluginCertTTL},
		ClientCertRotationAge: &rotationAdapter{m: execPluginCertRotation},
		RequestLatency:        &latencyAdapter{m: requestLatency, dm: deprecatedRequestLatency},
		RequestResult:         &resultAdapter{requestResult},
	})
}

type latencyAdapter struct {
	m  *k8smetrics.HistogramVec
	dm *k8smetrics.HistogramVec
}

func (l *latencyAdapter) Observe(verb string, u url.URL, latency time.Duration) {
	l.m.WithLabelValues(verb, u.String()).Observe(latency.Seconds())
	l.dm.WithLabelValues(verb, u.String()).Observe(latency.Seconds())
}

type resultAdapter struct {
	m *k8smetrics.CounterVec
}

func (r *resultAdapter) Increment(code, method, host string) {
	r.m.WithLabelValues(code, method, host).Inc()
}

type ttlAdapter struct {
	m *k8smetrics.Gauge
}

func (e *ttlAdapter) Set(ttl *time.Duration) {
	if ttl == nil {
		e.m.Set(math.Inf(1))
	} else {
		e.m.Set(float64(ttl.Seconds()))
	}
}

type rotationAdapter struct {
	m *k8smetrics.Histogram
}

func (r *rotationAdapter) Observe(d time.Duration) {
	r.m.Observe(d.Seconds())
}
<commit_msg>Changed Kubelet client and serving cert TTL/Expiry certs to use gaugefunc for calculating time remaining.<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package restclient

import (
	"math"
	"net/url"
	"time"

	"k8s.io/client-go/tools/metrics"
	k8smetrics "k8s.io/component-base/metrics"
	"k8s.io/component-base/metrics/legacyregistry"
)

var (
	// requestLatency is a Prometheus Summary metric type partitioned by
	// "verb" and "url" labels. It is used for the rest client latency metrics.
	requestLatency = k8smetrics.NewHistogramVec(
		&k8smetrics.HistogramOpts{
			Name:    "rest_client_request_duration_seconds",
			Help:    "Request latency in seconds. Broken down by verb and URL.",
			Buckets: k8smetrics.ExponentialBuckets(0.001, 2, 10),
		},
		[]string{"verb", "url"},
	)

	// deprecatedRequestLatency is deprecated, please use requestLatency.
	deprecatedRequestLatency = k8smetrics.NewHistogramVec(
		&k8smetrics.HistogramOpts{
			Name:              "rest_client_request_latency_seconds",
			Help:              "Request latency in seconds. Broken down by verb and URL.",
			Buckets:           k8smetrics.ExponentialBuckets(0.001, 2, 10),
			DeprecatedVersion: "1.14.0",
		},
		[]string{"verb", "url"},
	)

	requestResult = k8smetrics.NewCounterVec(
		&k8smetrics.CounterOpts{
			Name: "rest_client_requests_total",
			Help: "Number of HTTP requests, partitioned by status code, method, and host.",
		},
		[]string{"code", "method", "host"},
	)

	execPluginCertTTLAdapter = &expiryToTTLAdapter{}

	execPluginCertTTL = k8smetrics.NewGaugeFunc(
		k8smetrics.GaugeOpts{
			Name: "rest_client_exec_plugin_ttl_seconds",
			Help: "Gauge of the shortest TTL (time-to-live) of the client " +
				"certificate(s) managed by the auth exec plugin. The value " +
				"is in seconds until certificate expiry (negative if " +
				"already expired). If auth exec plugins are unused or manage no " +
				"TLS certificates, the value will be +INF.",
			StabilityLevel: k8smetrics.ALPHA,
		},
		func() float64 {
			if execPluginCertTTLAdapter.e == nil {
				return math.Inf(1)
			}
			return execPluginCertTTLAdapter.e.Sub(time.Now()).Seconds()
		},
	)

	execPluginCertRotation = k8smetrics.NewHistogram(
		&k8smetrics.HistogramOpts{
			Name: "rest_client_exec_plugin_certificate_rotation_age",
			Help: "Histogram of the number of seconds the last auth exec " +
				"plugin client certificate lived before being rotated. " +
				"If auth exec plugin client certificates are unused, " +
				"histogram will contain no data.",
			// There are three sets of ranges these buckets intend to capture:
			//   - 10-60 minutes: captures a rotation cadence which is
			//     happening too quickly.
			//   - 4 hours - 1 month: captures an ideal rotation cadence.
			//   - 3 months - 4 years: captures a rotation cadence which is
			//     is probably too slow or much too slow.
			Buckets: []float64{
				600,       // 10 minutes
				1800,      // 30 minutes
				3600,      // 1  hour
				14400,     // 4  hours
				86400,     // 1  day
				604800,    // 1  week
				2592000,   // 1  month
				7776000,   // 3  months
				15552000,  // 6  months
				31104000,  // 1  year
				124416000, // 4  years
			},
		},
	)
)

func init() {

	legacyregistry.MustRegister(requestLatency)
	legacyregistry.MustRegister(deprecatedRequestLatency)
	legacyregistry.MustRegister(requestResult)
	legacyregistry.RawMustRegister(execPluginCertTTL)
	legacyregistry.MustRegister(execPluginCertRotation)
	metrics.Register(metrics.RegisterOpts{
		ClientCertExpiry:      execPluginCertTTLAdapter,
		ClientCertRotationAge: &rotationAdapter{m: execPluginCertRotation},
		RequestLatency:        &latencyAdapter{m: requestLatency, dm: deprecatedRequestLatency},
		RequestResult:         &resultAdapter{requestResult},
	})
}

type latencyAdapter struct {
	m  *k8smetrics.HistogramVec
	dm *k8smetrics.HistogramVec
}

func (l *latencyAdapter) Observe(verb string, u url.URL, latency time.Duration) {
	l.m.WithLabelValues(verb, u.String()).Observe(latency.Seconds())
	l.dm.WithLabelValues(verb, u.String()).Observe(latency.Seconds())
}

type resultAdapter struct {
	m *k8smetrics.CounterVec
}

func (r *resultAdapter) Increment(code, method, host string) {
	r.m.WithLabelValues(code, method, host).Inc()
}

type expiryToTTLAdapter struct {
	e *time.Time
}

func (e *expiryToTTLAdapter) Set(expiry *time.Time) {
	e.e = expiry
}

type rotationAdapter struct {
	m *k8smetrics.Histogram
}

func (r *rotationAdapter) Observe(d time.Duration) {
	r.m.Observe(d.Seconds())
}
<|endoftext|>


<commit_before>package options

import (
	"fmt"
	"github.com/mitchellh/go-homedir"
	"io"
	"log"
	"os"
	"path/filepath"
	"runtime"

	"github.com/gruntwork-io/terragrunt/errors"
	"github.com/gruntwork-io/terragrunt/util"
	"github.com/hashicorp/go-version"
)

var TERRAFORM_COMMANDS_WITH_SUBCOMMAND = []string{
	"debug",
	"force-unlock",
	"state",
}

const DEFAULT_MAX_FOLDERS_TO_CHECK = 100

// TerragruntOptions represents options that configure the behavior of the Terragrunt program
type TerragruntOptions struct {
	// Location of the Terragrunt config file
	TerragruntConfigPath string

	// Location of the terraform binary
	TerraformPath string

	// Version of terraform (obtained by running 'terraform version')
	TerraformVersion *version.Version

	// Whether we should prompt the user for confirmation or always assume "yes"
	NonInteractive bool

	// Whether we should automatically run terraform init if necessary when executing other commands
	AutoInit bool

	// CLI args that are intended for Terraform (i.e. all the CLI args except the --terragrunt ones)
	TerraformCliArgs []string

	// The working directory in which to run Terraform
	WorkingDir string

	// The logger to use for all logging
	Logger *log.Logger

	// Environment variables at runtime
	Env map[string]string

	// Download Terraform configurations from the specified source location into a temporary folder and run
	// Terraform in that temporary folder
	Source string

	// If set to true, delete the contents of the temporary folder before downloading Terraform source code into it
	SourceUpdate bool

	// Download Terraform configurations specified in the Source parameter into this folder
	DownloadDir string

	// The ARN of an IAM Role to assume before running Terraform
	IamRole string

	// If set to true, continue running *-all commands even if a dependency has errors. This is mostly useful for 'output-all <some_variable>'. See https://github.com/gruntwork-io/terragrunt/issues/193
	IgnoreDependencyErrors bool

	// If you want stdout to go somewhere other than os.stdout
	Writer io.Writer

	// If you want stderr to go somewhere other than os.stderr
	ErrWriter io.Writer

	// When searching the directory tree, this is the max folders to check before exiting with an error. This is
	// exposed here primarily so we can set it to a low value at test time.
	MaxFoldersToCheck int

	// A command that can be used to run Terragrunt with the given options. This is useful for running Terragrunt
	// multiple times (e.g. when spinning up a stack of Terraform modules). The actual command is normally defined
	// in the cli package, which depends on almost all other packages, so we declare it here so that other
	// packages can use the command without a direct reference back to the cli package (which would create a
	// circular dependency).
	RunTerragrunt func(*TerragruntOptions) error
}

// Create a new TerragruntOptions object with reasonable defaults for real usage
func NewTerragruntOptions(terragruntConfigPath string) (*TerragruntOptions, error) {
	workingDir := filepath.Dir(terragruntConfigPath)

	logger := util.CreateLogger("")

	homedir, err := homedir.Dir()
	if err != nil {
		logger.Printf("error: %v\n", err)
		return nil, err
	}

	downloadDir := filepath.Join(homedir, ".terragrunt")
	// On some versions of Windows, the default temp dir is a fairly long path (e.g. C:/Users/JONDOE~1/AppData/Local/Temp/2/).
	// This is a problem because Windows also limits path lengths to 260 characters, and with nested folders and hashed folder names
	// (e.g. from running terraform get), you can hit that limit pretty quickly. Therefore, we try to set the temporary download
	// folder to something slightly shorter, but still reasonable.
	if runtime.GOOS == "windows" {
		downloadDir = `C:\\Windows\\Temp\\terragrunt`
	}

	return &TerragruntOptions{
		TerragruntConfigPath:   terragruntConfigPath,
		TerraformPath:          "terraform",
		AutoInit:               true,
		NonInteractive:         false,
		TerraformCliArgs:       []string{},
		WorkingDir:             workingDir,
		Logger:                 logger,
		Env:                    map[string]string{},
		Source:                 "",
		SourceUpdate:           false,
		DownloadDir:            downloadDir,
		IgnoreDependencyErrors: false,
		Writer:                 os.Stdout,
		ErrWriter:              os.Stderr,
		MaxFoldersToCheck:      DEFAULT_MAX_FOLDERS_TO_CHECK,
		RunTerragrunt: func(terragruntOptions *TerragruntOptions) error {
			return errors.WithStackTrace(RunTerragruntCommandNotSet)
		},
	}, nil
}

// Create a new TerragruntOptions object with reasonable defaults for test usage
func NewTerragruntOptionsForTest(terragruntConfigPath string) (*TerragruntOptions, error) {
	opts, err := NewTerragruntOptions(terragruntConfigPath)

	if err != nil {
		logger := util.CreateLogger("")
		logger.Printf("error: %v\n", errors.WithStackTrace(err))
		return nil, err
	}

	opts.NonInteractive = true

	return opts, nil
}

// Create a copy of this TerragruntOptions, but with different values for the given variables. This is useful for
// creating a TerragruntOptions that behaves the same way, but is used for a Terraform module in a different folder.
func (terragruntOptions *TerragruntOptions) Clone(terragruntConfigPath string) *TerragruntOptions {
	workingDir := filepath.Dir(terragruntConfigPath)

	// Note that we clone lists and maps below as TerragruntOptions may be used and modified concurrently in the code
	// during xxx-all commands (e.g., apply-all, plan-all). See https://github.com/gruntwork-io/terragrunt/issues/367
	// for more info.
	return &TerragruntOptions{
		TerragruntConfigPath:   terragruntConfigPath,
		TerraformPath:          terragruntOptions.TerraformPath,
		TerraformVersion:       terragruntOptions.TerraformVersion,
		AutoInit:               terragruntOptions.AutoInit,
		NonInteractive:         terragruntOptions.NonInteractive,
		TerraformCliArgs:       util.CloneStringList(terragruntOptions.TerraformCliArgs),
		WorkingDir:             workingDir,
		Logger:                 util.CreateLoggerWithWriter(terragruntOptions.ErrWriter, workingDir),
		Env:                    util.CloneStringMap(terragruntOptions.Env),
		Source:                 terragruntOptions.Source,
		SourceUpdate:           terragruntOptions.SourceUpdate,
		DownloadDir:            terragruntOptions.DownloadDir,
		IamRole:                terragruntOptions.IamRole,
		IgnoreDependencyErrors: terragruntOptions.IgnoreDependencyErrors,
		Writer:                 terragruntOptions.Writer,
		ErrWriter:              terragruntOptions.ErrWriter,
		MaxFoldersToCheck:      terragruntOptions.MaxFoldersToCheck,
		RunTerragrunt:          terragruntOptions.RunTerragrunt,
	}
}

// Inserts the given argsToInsert after the terraform command argument, but before the remaining args
func (terragruntOptions *TerragruntOptions) InsertTerraformCliArgs(argsToInsert ...string) {

	commandLength := 1
	if util.ListContainsElement(TERRAFORM_COMMANDS_WITH_SUBCOMMAND, terragruntOptions.TerraformCliArgs[0]) {
		commandLength = 2
	}

	// Options must be inserted after command but before the other args
	// command is either 1 word or 2 words
	var args []string
	args = append(args, terragruntOptions.TerraformCliArgs[:commandLength]...)
	args = append(args, argsToInsert...)
	args = append(args, terragruntOptions.TerraformCliArgs[commandLength:]...)
	terragruntOptions.TerraformCliArgs = args
}

// Appends the given argsToAppend after the current TerraformCliArgs
func (terragruntOptions *TerragruntOptions) AppendTerraformCliArgs(argsToAppend ...string) {
	terragruntOptions.TerraformCliArgs = append(terragruntOptions.TerraformCliArgs, argsToAppend...)
}

// Custom error types

var RunTerragruntCommandNotSet = fmt.Errorf("The RunTerragrunt option has not been set on this TerragruntOptions object")
<commit_msg>take min of 2 or TerraformCliArgs to avoid out of bounds slice error<commit_after>package options

import (
	"fmt"
	"github.com/mitchellh/go-homedir"
	"io"
	"log"
	"os"
	"path/filepath"
	"runtime"

	"github.com/gruntwork-io/terragrunt/errors"
	"github.com/gruntwork-io/terragrunt/util"
	"github.com/hashicorp/go-version"
)

var TERRAFORM_COMMANDS_WITH_SUBCOMMAND = []string{
	"debug",
	"force-unlock",
	"state",
}

const DEFAULT_MAX_FOLDERS_TO_CHECK = 100

// TerragruntOptions represents options that configure the behavior of the Terragrunt program
type TerragruntOptions struct {
	// Location of the Terragrunt config file
	TerragruntConfigPath string

	// Location of the terraform binary
	TerraformPath string

	// Version of terraform (obtained by running 'terraform version')
	TerraformVersion *version.Version

	// Whether we should prompt the user for confirmation or always assume "yes"
	NonInteractive bool

	// Whether we should automatically run terraform init if necessary when executing other commands
	AutoInit bool

	// CLI args that are intended for Terraform (i.e. all the CLI args except the --terragrunt ones)
	TerraformCliArgs []string

	// The working directory in which to run Terraform
	WorkingDir string

	// The logger to use for all logging
	Logger *log.Logger

	// Environment variables at runtime
	Env map[string]string

	// Download Terraform configurations from the specified source location into a temporary folder and run
	// Terraform in that temporary folder
	Source string

	// If set to true, delete the contents of the temporary folder before downloading Terraform source code into it
	SourceUpdate bool

	// Download Terraform configurations specified in the Source parameter into this folder
	DownloadDir string

	// The ARN of an IAM Role to assume before running Terraform
	IamRole string

	// If set to true, continue running *-all commands even if a dependency has errors. This is mostly useful for 'output-all <some_variable>'. See https://github.com/gruntwork-io/terragrunt/issues/193
	IgnoreDependencyErrors bool

	// If you want stdout to go somewhere other than os.stdout
	Writer io.Writer

	// If you want stderr to go somewhere other than os.stderr
	ErrWriter io.Writer

	// When searching the directory tree, this is the max folders to check before exiting with an error. This is
	// exposed here primarily so we can set it to a low value at test time.
	MaxFoldersToCheck int

	// A command that can be used to run Terragrunt with the given options. This is useful for running Terragrunt
	// multiple times (e.g. when spinning up a stack of Terraform modules). The actual command is normally defined
	// in the cli package, which depends on almost all other packages, so we declare it here so that other
	// packages can use the command without a direct reference back to the cli package (which would create a
	// circular dependency).
	RunTerragrunt func(*TerragruntOptions) error
}

// Create a new TerragruntOptions object with reasonable defaults for real usage
func NewTerragruntOptions(terragruntConfigPath string) (*TerragruntOptions, error) {
	workingDir := filepath.Dir(terragruntConfigPath)

	logger := util.CreateLogger("")

	homedir, err := homedir.Dir()
	if err != nil {
		logger.Printf("error: %v\n", err)
		return nil, err
	}

	downloadDir := filepath.Join(homedir, ".terragrunt")
	// On some versions of Windows, the default temp dir is a fairly long path (e.g. C:/Users/JONDOE~1/AppData/Local/Temp/2/).
	// This is a problem because Windows also limits path lengths to 260 characters, and with nested folders and hashed folder names
	// (e.g. from running terraform get), you can hit that limit pretty quickly. Therefore, we try to set the temporary download
	// folder to something slightly shorter, but still reasonable.
	if runtime.GOOS == "windows" {
		downloadDir = `C:\\Windows\\Temp\\terragrunt`
	}

	return &TerragruntOptions{
		TerragruntConfigPath:   terragruntConfigPath,
		TerraformPath:          "terraform",
		AutoInit:               true,
		NonInteractive:         false,
		TerraformCliArgs:       []string{},
		WorkingDir:             workingDir,
		Logger:                 logger,
		Env:                    map[string]string{},
		Source:                 "",
		SourceUpdate:           false,
		DownloadDir:            downloadDir,
		IgnoreDependencyErrors: false,
		Writer:                 os.Stdout,
		ErrWriter:              os.Stderr,
		MaxFoldersToCheck:      DEFAULT_MAX_FOLDERS_TO_CHECK,
		RunTerragrunt: func(terragruntOptions *TerragruntOptions) error {
			return errors.WithStackTrace(RunTerragruntCommandNotSet)
		},
	}, nil
}

// Create a new TerragruntOptions object with reasonable defaults for test usage
func NewTerragruntOptionsForTest(terragruntConfigPath string) (*TerragruntOptions, error) {
	opts, err := NewTerragruntOptions(terragruntConfigPath)

	if err != nil {
		logger := util.CreateLogger("")
		logger.Printf("error: %v\n", errors.WithStackTrace(err))
		return nil, err
	}

	opts.NonInteractive = true

	return opts, nil
}

// Create a copy of this TerragruntOptions, but with different values for the given variables. This is useful for
// creating a TerragruntOptions that behaves the same way, but is used for a Terraform module in a different folder.
func (terragruntOptions *TerragruntOptions) Clone(terragruntConfigPath string) *TerragruntOptions {
	workingDir := filepath.Dir(terragruntConfigPath)

	// Note that we clone lists and maps below as TerragruntOptions may be used and modified concurrently in the code
	// during xxx-all commands (e.g., apply-all, plan-all). See https://github.com/gruntwork-io/terragrunt/issues/367
	// for more info.
	return &TerragruntOptions{
		TerragruntConfigPath:   terragruntConfigPath,
		TerraformPath:          terragruntOptions.TerraformPath,
		TerraformVersion:       terragruntOptions.TerraformVersion,
		AutoInit:               terragruntOptions.AutoInit,
		NonInteractive:         terragruntOptions.NonInteractive,
		TerraformCliArgs:       util.CloneStringList(terragruntOptions.TerraformCliArgs),
		WorkingDir:             workingDir,
		Logger:                 util.CreateLoggerWithWriter(terragruntOptions.ErrWriter, workingDir),
		Env:                    util.CloneStringMap(terragruntOptions.Env),
		Source:                 terragruntOptions.Source,
		SourceUpdate:           terragruntOptions.SourceUpdate,
		DownloadDir:            terragruntOptions.DownloadDir,
		IamRole:                terragruntOptions.IamRole,
		IgnoreDependencyErrors: terragruntOptions.IgnoreDependencyErrors,
		Writer:                 terragruntOptions.Writer,
		ErrWriter:              terragruntOptions.ErrWriter,
		MaxFoldersToCheck:      terragruntOptions.MaxFoldersToCheck,
		RunTerragrunt:          terragruntOptions.RunTerragrunt,
	}
}

// Inserts the given argsToInsert after the terraform command argument, but before the remaining args
func (terragruntOptions *TerragruntOptions) InsertTerraformCliArgs(argsToInsert ...string) {

	commandLength := 1
	if util.ListContainsElement(TERRAFORM_COMMANDS_WITH_SUBCOMMAND, terragruntOptions.TerraformCliArgs[0]) {
		// Since these terraform commands require subcommands which may not always be properly passed by the user,
		// using util.Min to return the minimum to avoid potential out of bounds slice errors.
		commandLength = util.Min(2, len(terragruntOptions.TerraformCliArgs))
	}

	// Options must be inserted after command but before the other args
	// command is either 1 word or 2 words
	var args []string
	args = append(args, terragruntOptions.TerraformCliArgs[:commandLength]...)
	args = append(args, argsToInsert...)
	args = append(args, terragruntOptions.TerraformCliArgs[commandLength:]...)
	terragruntOptions.TerraformCliArgs = args
}

// Appends the given argsToAppend after the current TerraformCliArgs
func (terragruntOptions *TerragruntOptions) AppendTerraformCliArgs(argsToAppend ...string) {
	terragruntOptions.TerraformCliArgs = append(terragruntOptions.TerraformCliArgs, argsToAppend...)
}

// Custom error types

var RunTerragruntCommandNotSet = fmt.Errorf("The RunTerragrunt option has not been set on this TerragruntOptions object")
<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.

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

package tchannel_test

import (
	"runtime"
	"testing"
	"time"

	. "github.com/uber/tchannel-go"

	"github.com/uber/tchannel-go/testutils"
)

func waitForChannelClose(t *testing.T, ch *Channel) bool {
	var state ChannelState
	for i := 0; i < 20; i++ {
		if state = ch.State(); state == ChannelClosed {
			return true
		}

		if i > 5 {
			time.Sleep(time.Millisecond)
		} else {
			runtime.Gosched()
		}
	}

	// Channel is not closing, fail the test.
	t.Errorf("Channel did not close, last state: %v", state)
	return false
}

// WithVerifiedServer runs the given test function with a server channel that is verified
// at the end to make sure there are no leaks (e.g. no exchanges leaked).
func WithVerifiedServer(t *testing.T, opts *testutils.ChannelOpts, f func(serverCh *Channel, hostPort string)) {
	var ch *Channel
	testutils.WithServer(t, opts, func(serverCh *Channel, hostPort string) {
		f(serverCh, hostPort)
		ch = serverCh
	})

	if !waitForChannelClose(t, ch) {
		return
	}

	// Check the message exchanges and make sure they are all empty.
	if exchangesLeft := CheckEmptyExchanges(ch); exchangesLeft != "" {
		t.Errorf("Found uncleared message exchanges:\n%v", exchangesLeft)
	}
}
<commit_msg>waitForChannelClose should account for timeoutMultiplier<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.

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

package tchannel_test

import (
	"runtime"
	"testing"
	"time"

	. "github.com/uber/tchannel-go"

	"github.com/uber/tchannel-go/testutils"
)

func waitForChannelClose(t *testing.T, ch *Channel) bool {
	started := time.Now()

	var state ChannelState
	for i := 0; i < 20; i++ {
		if state = ch.State(); state == ChannelClosed {
			return true
		}

		runtime.Gosched()
		if i < 5 {
			continue
		}

		sleepFor := time.Duration(i) * 100 * time.Microsecond
		time.Sleep(testutils.Timeout(sleepFor))
	}

	// Channel is not closing, fail the test.
	sinceStart := time.Since(started)
	t.Errorf("Channel did not close after %v, last state: %v", sinceStart, state)
	return false
}

// WithVerifiedServer runs the given test function with a server channel that is verified
// at the end to make sure there are no leaks (e.g. no exchanges leaked).
func WithVerifiedServer(t *testing.T, opts *testutils.ChannelOpts, f func(serverCh *Channel, hostPort string)) {
	var ch *Channel
	testutils.WithServer(t, opts, func(serverCh *Channel, hostPort string) {
		f(serverCh, hostPort)
		ch = serverCh
	})

	if !waitForChannelClose(t, ch) {
		return
	}

	// Check the message exchanges and make sure they are all empty.
	if exchangesLeft := CheckEmptyExchanges(ch); exchangesLeft != "" {
		t.Errorf("Found uncleared message exchanges:\n%v", exchangesLeft)
	}
}
<|endoftext|>


<commit_before>package tccp

const RecordSets = `
{{define "record_sets"}}
{{- $v := .Guest.RecordSets }}
{{ if $v.Route53Enabled }}
  HostedZone:
    Type: 'AWS::Route53::HostedZone'
    Properties:
      Name: '{{ $v.ClusterID }}.k8s.{{ $v.BaseDomain }}.'
  InternalHostedZone:
    Type: 'AWS::Route53::HostedZone'
    Properties:
      Name: '{{ $v.ClusterID }}.k8s.{{ $v.BaseDomain }}.'
      HostedZoneConfig:
        Comment: "Internal hosted zone for internal network"
      VPCs:
        - VPCId: !Ref VPC
          VPCRegion: '{{ $v.VPCRegion }}'
  ApiRecordSet:
    Type: AWS::Route53::RecordSet
    Properties:
      AliasTarget:
        DNSName: !GetAtt ApiLoadBalancer.DNSName
        HostedZoneId: !GetAtt ApiLoadBalancer.CanonicalHostedZoneNameID
        EvaluateTargetHealth: false
      Name: 'api.{{ $v.ClusterID }}.k8s.{{ $v.BaseDomain }}.'
      HostedZoneId: !Ref 'HostedZone'
      Type: A
  ApiInternalRecordSet:
    Type: AWS::Route53::RecordSet
    Properties:
      AliasTarget:
        DNSName: !GetAtt ApiInternalLoadBalancer.DNSName
        HostedZoneId: !GetAtt ApiInternalLoadBalancer.CanonicalHostedZoneNameID
        EvaluateTargetHealth: false
      Name: 'api.{{ $v.ClusterID }}.k8s.{{ $v.BaseDomain }}.'
      HostedZoneId: !Ref 'InternalHostedZone'
      Type: A
  EtcdInternalRecordSet:
    Type: AWS::Route53::RecordSet
    Properties:
      AliasTarget:
        DNSName: !GetAtt EtcdLoadBalancer.DNSName
        HostedZoneId: !GetAtt EtcdLoadBalancer.CanonicalHostedZoneNameID
        EvaluateTargetHealth: false
      Name: '{{ $v.EtcdDomain }}.'
      HostedZoneId: !Ref 'InternalHostedZone'
      Type: A
  EtcdRecordSet:
    Type: AWS::Route53::RecordSet
    Properties:
      AliasTarget:
        DNSName: !GetAtt EtcdLoadBalancer.DNSName
        HostedZoneId: !GetAtt EtcdLoadBalancer.CanonicalHostedZoneNameID
        EvaluateTargetHealth: false
      Name: '{{ $v.EtcdDomain }}.'
      HostedZoneId: !Ref 'HostedZone'
      Type: A
  IngressInternalRecordSet:
    Type: AWS::Route53::RecordSet
    Properties:
      AliasTarget:
        DNSName: !GetAtt IngressInternalLoadBalancer.DNSName
        HostedZoneId: !GetAtt IngressInternalLoadBalancer.CanonicalHostedZoneNameID
        EvaluateTargetHealth: false
      Name: 'ingress.{{ $v.ClusterID }}.k8s.{{ $v.BaseDomain }}.'
      HostedZoneId: !Ref 'InternalHostedZone'
      Type: A
  IngressInternalWildcardRecordSet:
    Type: AWS::Route53::RecordSet
    Properties:
      Name: '*.{{ $v.ClusterID }}.k8s.{{ $v.BaseDomain }}.'
      HostedZoneId: !Ref 'InternalHostedZone'
      TTL: '300'
      Type: CNAME
      ResourceRecords:
        - !Ref 'IngressInternalRecordSet'
  IngressRecordSet:
    Type: AWS::Route53::RecordSet
    Properties:
      AliasTarget:
        DNSName: !GetAtt IngressLoadBalancer.DNSName
        HostedZoneId: !GetAtt IngressLoadBalancer.CanonicalHostedZoneNameID
        EvaluateTargetHealth: false
      Name: 'ingress.{{ $v.ClusterID }}.k8s.{{ $v.BaseDomain }}.'
      HostedZoneId: !Ref 'HostedZone'
      Type: A
  IngressWildcardRecordSet:
    Type: AWS::Route53::RecordSet
    Properties:
      Name: '*.{{ $v.ClusterID }}.k8s.{{ $v.BaseDomain }}.'
      HostedZoneId: !Ref 'HostedZone'
      TTL: '300'
      Type: CNAME
      ResourceRecords:
        - !Ref 'IngressRecordSet'
{{end}}
{{end}}
`
<commit_msg>Change recordet names<commit_after>package tccp

const RecordSets = `
{{define "record_sets"}}
{{- $v := .Guest.RecordSets }}
{{ if $v.Route53Enabled }}
  HostedZone:
    Type: 'AWS::Route53::HostedZone'
    Properties:
      Name: '{{ $v.ClusterID }}.k8s.{{ $v.BaseDomain }}.'
  InternalHostedZone:
    Type: 'AWS::Route53::HostedZone'
    Properties:
      Name: '{{ $v.ClusterID }}.k8s.{{ $v.BaseDomain }}.'
      HostedZoneConfig:
        Comment: "Internal hosted zone for internal network"
      VPCs:
        - VPCId: !Ref VPC
          VPCRegion: '{{ $v.VPCRegion }}'
  ApiRecordSet:
    Type: AWS::Route53::RecordSet
    Properties:
      AliasTarget:
        DNSName: !GetAtt ApiLoadBalancer.DNSName
        HostedZoneId: !GetAtt ApiLoadBalancer.CanonicalHostedZoneNameID
        EvaluateTargetHealth: false
      Name: 'api.{{ $v.ClusterID }}.k8s.{{ $v.BaseDomain }}.'
      HostedZoneId: !Ref 'HostedZone'
      Type: A
  ApiInternalRecordSet:
    Type: AWS::Route53::RecordSet
    Properties:
      AliasTarget:
        DNSName: !GetAtt ApiInternalLoadBalancer.DNSName
        HostedZoneId: !GetAtt ApiInternalLoadBalancer.CanonicalHostedZoneNameID
        EvaluateTargetHealth: false
      Name: 'api.{{ $v.ClusterID }}.k8s.{{ $v.BaseDomain }}.'
      HostedZoneId: !Ref 'InternalHostedZone'
      Type: A
  EtcdRecordSet:
    Type: AWS::Route53::RecordSet
    Properties:
      AliasTarget:
        DNSName: !GetAtt EtcdLoadBalancer.DNSName
        HostedZoneId: !GetAtt EtcdLoadBalancer.CanonicalHostedZoneNameID
        EvaluateTargetHealth: false
      Name: '{{ $v.EtcdDomain }}.'
      HostedZoneId: !Ref 'InternalHostedZone'
      Type: A
  EtcdExternalRecordSet:
    Type: AWS::Route53::RecordSet
    Properties:
      AliasTarget:
        DNSName: !GetAtt EtcdLoadBalancer.DNSName
        HostedZoneId: !GetAtt EtcdLoadBalancer.CanonicalHostedZoneNameID
        EvaluateTargetHealth: false
      Name: '{{ $v.EtcdDomain }}.'
      HostedZoneId: !Ref 'HostedZone'
      Type: A
  IngressInternalRecordSet:
    Type: AWS::Route53::RecordSet
    Properties:
      AliasTarget:
        DNSName: !GetAtt IngressInternalLoadBalancer.DNSName
        HostedZoneId: !GetAtt IngressInternalLoadBalancer.CanonicalHostedZoneNameID
        EvaluateTargetHealth: false
      Name: 'ingress.{{ $v.ClusterID }}.k8s.{{ $v.BaseDomain }}.'
      HostedZoneId: !Ref 'InternalHostedZone'
      Type: A
  IngressInternalWildcardRecordSet:
    Type: AWS::Route53::RecordSet
    Properties:
      Name: '*.{{ $v.ClusterID }}.k8s.{{ $v.BaseDomain }}.'
      HostedZoneId: !Ref 'InternalHostedZone'
      TTL: '300'
      Type: CNAME
      ResourceRecords:
        - !Ref 'IngressInternalRecordSet'
  IngressRecordSet:
    Type: AWS::Route53::RecordSet
    Properties:
      AliasTarget:
        DNSName: !GetAtt IngressLoadBalancer.DNSName
        HostedZoneId: !GetAtt IngressLoadBalancer.CanonicalHostedZoneNameID
        EvaluateTargetHealth: false
      Name: 'ingress.{{ $v.ClusterID }}.k8s.{{ $v.BaseDomain }}.'
      HostedZoneId: !Ref 'HostedZone'
      Type: A
  IngressWildcardRecordSet:
    Type: AWS::Route53::RecordSet
    Properties:
      Name: '*.{{ $v.ClusterID }}.k8s.{{ $v.BaseDomain }}.'
      HostedZoneId: !Ref 'HostedZone'
      TTL: '300'
      Type: CNAME
      ResourceRecords:
        - !Ref 'IngressRecordSet'
{{end}}
{{end}}
`
<|endoftext|>