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

package mime

import (
	"errors"
	"fmt"
	"sort"
	"strings"
	"unicode"
)

// FormatMediaType serializes mediatype t and the parameters
// param as a media type conforming to RFC 2045 and RFC 2616.
// The type and parameter names are written in lower-case.
// When any of the arguments result in a standard violation then
// FormatMediaType returns the empty string.
func FormatMediaType(t string, param map[string]string) string {
	var b strings.Builder
	if slash := strings.Index(t, "/"); slash == -1 {
		if !isToken(t) {
			return ""
		}
		b.WriteString(strings.ToLower(t))
	} else {
		major, sub := t[:slash], t[slash+1:]
		if !isToken(major) || !isToken(sub) {
			return ""
		}
		b.WriteString(strings.ToLower(major))
		b.WriteByte('/')
		b.WriteString(strings.ToLower(sub))
	}

	attrs := make([]string, 0, len(param))
	for a := range param {
		attrs = append(attrs, a)
	}
	sort.Strings(attrs)

	for _, attribute := range attrs {
		value := param[attribute]
		b.WriteByte(';')
		b.WriteByte(' ')
		if !isToken(attribute) {
			return ""
		}
		b.WriteString(strings.ToLower(attribute))
		b.WriteByte('=')
		if isToken(value) {
			b.WriteString(value)
			continue
		}

		b.WriteByte('"')
		offset := 0
		for index, character := range []byte(value) {
			if character == '"' || character == '\\' {
				b.WriteString(value[offset:index])
				offset = index
				b.WriteByte('\\')
			}
			if character&0x80 != 0 {
				return ""
			}
		}
		b.WriteString(value[offset:])
		b.WriteByte('"')
	}
	return b.String()
}

func checkMediaTypeDisposition(s string) error {
	typ, rest := consumeToken(s)
	if typ == "" {
		return errors.New("mime: no media type")
	}
	if rest == "" {
		return nil
	}
	if !strings.HasPrefix(rest, "/") {
		return errors.New("mime: expected slash after first token")
	}
	subtype, rest := consumeToken(rest[1:])
	if subtype == "" {
		return errors.New("mime: expected token after slash")
	}
	if rest != "" {
		return errors.New("mime: unexpected content after media subtype")
	}
	return nil
}

// ErrInvalidMediaParameter is returned by ParseMediaType if
// the media type value was found but there was an error parsing
// the optional parameters
var ErrInvalidMediaParameter = errors.New("mime: invalid media parameter")

// ParseMediaType parses a media type value and any optional
// parameters, per RFC 1521.  Media types are the values in
// Content-Type and Content-Disposition headers (RFC 2183).
// On success, ParseMediaType returns the media type converted
// to lowercase and trimmed of white space and a non-nil map.
// If there is an error parsing the optional parameter,
// the media type will be returned along with the error
// ErrInvalidMediaParameter.
// The returned map, params, maps from the lowercase
// attribute to the attribute value with its case preserved.
func ParseMediaType(v string) (mediatype string, params map[string]string, err error) {
	i := strings.Index(v, ";")
	if i == -1 {
		i = len(v)
	}
	mediatype = strings.TrimSpace(strings.ToLower(v[0:i]))

	err = checkMediaTypeDisposition(mediatype)
	if err != nil {
		return "", nil, err
	}

	params = make(map[string]string)

	// Map of base parameter name -> parameter name -> value
	// for parameters containing a '*' character.
	// Lazily initialized.
	var continuation map[string]map[string]string

	v = v[i:]
	for len(v) > 0 {
		v = strings.TrimLeftFunc(v, unicode.IsSpace)
		if len(v) == 0 {
			break
		}
		key, value, rest := consumeMediaParam(v)
		if key == "" {
			if strings.TrimSpace(rest) == ";" {
				// Ignore trailing semicolons.
				// Not an error.
				return
			}
			// Parse error.
			return mediatype, nil, ErrInvalidMediaParameter
		}

		pmap := params
		if idx := strings.Index(key, "*"); idx != -1 {
			baseName := key[:idx]
			if continuation == nil {
				continuation = make(map[string]map[string]string)
			}
			var ok bool
			if pmap, ok = continuation[baseName]; !ok {
				continuation[baseName] = make(map[string]string)
				pmap = continuation[baseName]
			}
		}
		if _, exists := pmap[key]; exists {
			// Duplicate parameter name is bogus.
			return "", nil, errors.New("mime: duplicate parameter name")
		}
		pmap[key] = value
		v = rest
	}

	// Stitch together any continuations or things with stars
	// (i.e. RFC 2231 things with stars: "foo*0" or "foo*")
	var buf strings.Builder
	for key, pieceMap := range continuation {
		singlePartKey := key + "*"
		if v, ok := pieceMap[singlePartKey]; ok {
			if decv, ok := decode2231Enc(v); ok {
				params[key] = decv
			}
			continue
		}

		buf.Reset()
		valid := false
		for n := 0; ; n++ {
			simplePart := fmt.Sprintf("%s*%d", key, n)
			if v, ok := pieceMap[simplePart]; ok {
				valid = true
				buf.WriteString(v)
				continue
			}
			encodedPart := simplePart + "*"
			v, ok := pieceMap[encodedPart]
			if !ok {
				break
			}
			valid = true
			if n == 0 {
				if decv, ok := decode2231Enc(v); ok {
					buf.WriteString(decv)
				}
			} else {
				decv, _ := percentHexUnescape(v)
				buf.WriteString(decv)
			}
		}
		if valid {
			params[key] = buf.String()
		}
	}

	return
}

func decode2231Enc(v string) (string, bool) {
	sv := strings.SplitN(v, "'", 3)
	if len(sv) != 3 {
		return "", false
	}
	// TODO: ignoring lang in sv[1] for now. If anybody needs it we'll
	// need to decide how to expose it in the API. But I'm not sure
	// anybody uses it in practice.
	charset := strings.ToLower(sv[0])
	if len(charset) == 0 {
		return "", false
	}
	if charset != "us-ascii" && charset != "utf-8" {
		// TODO: unsupported encoding
		return "", false
	}
	encv, err := percentHexUnescape(sv[2])
	if err != nil {
		return "", false
	}
	return encv, true
}

func isNotTokenChar(r rune) bool {
	return !isTokenChar(r)
}

// consumeToken consumes a token from the beginning of provided
// string, per RFC 2045 section 5.1 (referenced from 2183), and return
// the token consumed and the rest of the string. Returns ("", v) on
// failure to consume at least one character.
func consumeToken(v string) (token, rest string) {
	notPos := strings.IndexFunc(v, isNotTokenChar)
	if notPos == -1 {
		return v, ""
	}
	if notPos == 0 {
		return "", v
	}
	return v[0:notPos], v[notPos:]
}

// consumeValue consumes a "value" per RFC 2045, where a value is
// either a 'token' or a 'quoted-string'.  On success, consumeValue
// returns the value consumed (and de-quoted/escaped, if a
// quoted-string) and the rest of the string. On failure, returns
// ("", v).
func consumeValue(v string) (value, rest string) {
	if v == "" {
		return
	}
	if v[0] != '"' {
		return consumeToken(v)
	}

	// parse a quoted-string
	buffer := new(strings.Builder)
	for i := 1; i < len(v); i++ {
		r := v[i]
		if r == '"' {
			return buffer.String(), v[i+1:]
		}
		// When MSIE sends a full file path (in "intranet mode"), it does not
		// escape backslashes: "C:\dev\go\foo.txt", not "C:\\dev\\go\\foo.txt".
		//
		// No known MIME generators emit unnecessary backslash escapes
		// for simple token characters like numbers and letters.
		//
		// If we see an unnecessary backslash escape, assume it is from MSIE
		// and intended as a literal backslash. This makes Go servers deal better
		// with MSIE without affecting the way they handle conforming MIME
		// generators.
		if r == '\\' && i+1 < len(v) && isTSpecial(rune(v[i+1])) {
			buffer.WriteByte(v[i+1])
			i++
			continue
		}
		if r == '\r' || r == '\n' {
			return "", v
		}
		buffer.WriteByte(v[i])
	}
	// Did not find end quote.
	return "", v
}

func consumeMediaParam(v string) (param, value, rest string) {
	rest = strings.TrimLeftFunc(v, unicode.IsSpace)
	if !strings.HasPrefix(rest, ";") {
		return "", "", v
	}

	rest = rest[1:] // consume semicolon
	rest = strings.TrimLeftFunc(rest, unicode.IsSpace)
	param, rest = consumeToken(rest)
	param = strings.ToLower(param)
	if param == "" {
		return "", "", v
	}

	rest = strings.TrimLeftFunc(rest, unicode.IsSpace)
	if !strings.HasPrefix(rest, "=") {
		return "", "", v
	}
	rest = rest[1:] // consume equals sign
	rest = strings.TrimLeftFunc(rest, unicode.IsSpace)
	value, rest2 := consumeValue(rest)
	if value == "" && rest2 == rest {
		return "", "", v
	}
	rest = rest2
	return param, value, rest
}

func percentHexUnescape(s string) (string, error) {
	// Count %, check that they're well-formed.
	percents := 0
	for i := 0; i < len(s); {
		if s[i] != '%' {
			i++
			continue
		}
		percents++
		if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) {
			s = s[i:]
			if len(s) > 3 {
				s = s[0:3]
			}
			return "", fmt.Errorf("mime: bogus characters after %%: %q", s)
		}
		i += 3
	}
	if percents == 0 {
		return s, nil
	}

	t := make([]byte, len(s)-2*percents)
	j := 0
	for i := 0; i < len(s); {
		switch s[i] {
		case '%':
			t[j] = unhex(s[i+1])<<4 | unhex(s[i+2])
			j++
			i += 3
		default:
			t[j] = s[i]
			j++
			i++
		}
	}
	return string(t), nil
}

func ishex(c byte) bool {
	switch {
	case '0' <= c && c <= '9':
		return true
	case 'a' <= c && c <= 'f':
		return true
	case 'A' <= c && c <= 'F':
		return true
	}
	return false
}

func unhex(c byte) byte {
	switch {
	case '0' <= c && c <= '9':
		return c - '0'
	case 'a' <= c && c <= 'f':
		return c - 'a' + 10
	case 'A' <= c && c <= 'F':
		return c - 'A' + 10
	}
	return 0
}
<commit_msg>mime: remove allocation introduced in recent fix<commit_after>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package mime

import (
	"errors"
	"fmt"
	"sort"
	"strings"
	"unicode"
)

// FormatMediaType serializes mediatype t and the parameters
// param as a media type conforming to RFC 2045 and RFC 2616.
// The type and parameter names are written in lower-case.
// When any of the arguments result in a standard violation then
// FormatMediaType returns the empty string.
func FormatMediaType(t string, param map[string]string) string {
	var b strings.Builder
	if slash := strings.Index(t, "/"); slash == -1 {
		if !isToken(t) {
			return ""
		}
		b.WriteString(strings.ToLower(t))
	} else {
		major, sub := t[:slash], t[slash+1:]
		if !isToken(major) || !isToken(sub) {
			return ""
		}
		b.WriteString(strings.ToLower(major))
		b.WriteByte('/')
		b.WriteString(strings.ToLower(sub))
	}

	attrs := make([]string, 0, len(param))
	for a := range param {
		attrs = append(attrs, a)
	}
	sort.Strings(attrs)

	for _, attribute := range attrs {
		value := param[attribute]
		b.WriteByte(';')
		b.WriteByte(' ')
		if !isToken(attribute) {
			return ""
		}
		b.WriteString(strings.ToLower(attribute))
		b.WriteByte('=')
		if isToken(value) {
			b.WriteString(value)
			continue
		}

		b.WriteByte('"')
		offset := 0
		for index := 0; index < len(value); index++ {
			character := value[index]
			if character == '"' || character == '\\' {
				b.WriteString(value[offset:index])
				offset = index
				b.WriteByte('\\')
			}
			if character&0x80 != 0 {
				return ""
			}
		}
		b.WriteString(value[offset:])
		b.WriteByte('"')
	}
	return b.String()
}

func checkMediaTypeDisposition(s string) error {
	typ, rest := consumeToken(s)
	if typ == "" {
		return errors.New("mime: no media type")
	}
	if rest == "" {
		return nil
	}
	if !strings.HasPrefix(rest, "/") {
		return errors.New("mime: expected slash after first token")
	}
	subtype, rest := consumeToken(rest[1:])
	if subtype == "" {
		return errors.New("mime: expected token after slash")
	}
	if rest != "" {
		return errors.New("mime: unexpected content after media subtype")
	}
	return nil
}

// ErrInvalidMediaParameter is returned by ParseMediaType if
// the media type value was found but there was an error parsing
// the optional parameters
var ErrInvalidMediaParameter = errors.New("mime: invalid media parameter")

// ParseMediaType parses a media type value and any optional
// parameters, per RFC 1521.  Media types are the values in
// Content-Type and Content-Disposition headers (RFC 2183).
// On success, ParseMediaType returns the media type converted
// to lowercase and trimmed of white space and a non-nil map.
// If there is an error parsing the optional parameter,
// the media type will be returned along with the error
// ErrInvalidMediaParameter.
// The returned map, params, maps from the lowercase
// attribute to the attribute value with its case preserved.
func ParseMediaType(v string) (mediatype string, params map[string]string, err error) {
	i := strings.Index(v, ";")
	if i == -1 {
		i = len(v)
	}
	mediatype = strings.TrimSpace(strings.ToLower(v[0:i]))

	err = checkMediaTypeDisposition(mediatype)
	if err != nil {
		return "", nil, err
	}

	params = make(map[string]string)

	// Map of base parameter name -> parameter name -> value
	// for parameters containing a '*' character.
	// Lazily initialized.
	var continuation map[string]map[string]string

	v = v[i:]
	for len(v) > 0 {
		v = strings.TrimLeftFunc(v, unicode.IsSpace)
		if len(v) == 0 {
			break
		}
		key, value, rest := consumeMediaParam(v)
		if key == "" {
			if strings.TrimSpace(rest) == ";" {
				// Ignore trailing semicolons.
				// Not an error.
				return
			}
			// Parse error.
			return mediatype, nil, ErrInvalidMediaParameter
		}

		pmap := params
		if idx := strings.Index(key, "*"); idx != -1 {
			baseName := key[:idx]
			if continuation == nil {
				continuation = make(map[string]map[string]string)
			}
			var ok bool
			if pmap, ok = continuation[baseName]; !ok {
				continuation[baseName] = make(map[string]string)
				pmap = continuation[baseName]
			}
		}
		if _, exists := pmap[key]; exists {
			// Duplicate parameter name is bogus.
			return "", nil, errors.New("mime: duplicate parameter name")
		}
		pmap[key] = value
		v = rest
	}

	// Stitch together any continuations or things with stars
	// (i.e. RFC 2231 things with stars: "foo*0" or "foo*")
	var buf strings.Builder
	for key, pieceMap := range continuation {
		singlePartKey := key + "*"
		if v, ok := pieceMap[singlePartKey]; ok {
			if decv, ok := decode2231Enc(v); ok {
				params[key] = decv
			}
			continue
		}

		buf.Reset()
		valid := false
		for n := 0; ; n++ {
			simplePart := fmt.Sprintf("%s*%d", key, n)
			if v, ok := pieceMap[simplePart]; ok {
				valid = true
				buf.WriteString(v)
				continue
			}
			encodedPart := simplePart + "*"
			v, ok := pieceMap[encodedPart]
			if !ok {
				break
			}
			valid = true
			if n == 0 {
				if decv, ok := decode2231Enc(v); ok {
					buf.WriteString(decv)
				}
			} else {
				decv, _ := percentHexUnescape(v)
				buf.WriteString(decv)
			}
		}
		if valid {
			params[key] = buf.String()
		}
	}

	return
}

func decode2231Enc(v string) (string, bool) {
	sv := strings.SplitN(v, "'", 3)
	if len(sv) != 3 {
		return "", false
	}
	// TODO: ignoring lang in sv[1] for now. If anybody needs it we'll
	// need to decide how to expose it in the API. But I'm not sure
	// anybody uses it in practice.
	charset := strings.ToLower(sv[0])
	if len(charset) == 0 {
		return "", false
	}
	if charset != "us-ascii" && charset != "utf-8" {
		// TODO: unsupported encoding
		return "", false
	}
	encv, err := percentHexUnescape(sv[2])
	if err != nil {
		return "", false
	}
	return encv, true
}

func isNotTokenChar(r rune) bool {
	return !isTokenChar(r)
}

// consumeToken consumes a token from the beginning of provided
// string, per RFC 2045 section 5.1 (referenced from 2183), and return
// the token consumed and the rest of the string. Returns ("", v) on
// failure to consume at least one character.
func consumeToken(v string) (token, rest string) {
	notPos := strings.IndexFunc(v, isNotTokenChar)
	if notPos == -1 {
		return v, ""
	}
	if notPos == 0 {
		return "", v
	}
	return v[0:notPos], v[notPos:]
}

// consumeValue consumes a "value" per RFC 2045, where a value is
// either a 'token' or a 'quoted-string'.  On success, consumeValue
// returns the value consumed (and de-quoted/escaped, if a
// quoted-string) and the rest of the string. On failure, returns
// ("", v).
func consumeValue(v string) (value, rest string) {
	if v == "" {
		return
	}
	if v[0] != '"' {
		return consumeToken(v)
	}

	// parse a quoted-string
	buffer := new(strings.Builder)
	for i := 1; i < len(v); i++ {
		r := v[i]
		if r == '"' {
			return buffer.String(), v[i+1:]
		}
		// When MSIE sends a full file path (in "intranet mode"), it does not
		// escape backslashes: "C:\dev\go\foo.txt", not "C:\\dev\\go\\foo.txt".
		//
		// No known MIME generators emit unnecessary backslash escapes
		// for simple token characters like numbers and letters.
		//
		// If we see an unnecessary backslash escape, assume it is from MSIE
		// and intended as a literal backslash. This makes Go servers deal better
		// with MSIE without affecting the way they handle conforming MIME
		// generators.
		if r == '\\' && i+1 < len(v) && isTSpecial(rune(v[i+1])) {
			buffer.WriteByte(v[i+1])
			i++
			continue
		}
		if r == '\r' || r == '\n' {
			return "", v
		}
		buffer.WriteByte(v[i])
	}
	// Did not find end quote.
	return "", v
}

func consumeMediaParam(v string) (param, value, rest string) {
	rest = strings.TrimLeftFunc(v, unicode.IsSpace)
	if !strings.HasPrefix(rest, ";") {
		return "", "", v
	}

	rest = rest[1:] // consume semicolon
	rest = strings.TrimLeftFunc(rest, unicode.IsSpace)
	param, rest = consumeToken(rest)
	param = strings.ToLower(param)
	if param == "" {
		return "", "", v
	}

	rest = strings.TrimLeftFunc(rest, unicode.IsSpace)
	if !strings.HasPrefix(rest, "=") {
		return "", "", v
	}
	rest = rest[1:] // consume equals sign
	rest = strings.TrimLeftFunc(rest, unicode.IsSpace)
	value, rest2 := consumeValue(rest)
	if value == "" && rest2 == rest {
		return "", "", v
	}
	rest = rest2
	return param, value, rest
}

func percentHexUnescape(s string) (string, error) {
	// Count %, check that they're well-formed.
	percents := 0
	for i := 0; i < len(s); {
		if s[i] != '%' {
			i++
			continue
		}
		percents++
		if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) {
			s = s[i:]
			if len(s) > 3 {
				s = s[0:3]
			}
			return "", fmt.Errorf("mime: bogus characters after %%: %q", s)
		}
		i += 3
	}
	if percents == 0 {
		return s, nil
	}

	t := make([]byte, len(s)-2*percents)
	j := 0
	for i := 0; i < len(s); {
		switch s[i] {
		case '%':
			t[j] = unhex(s[i+1])<<4 | unhex(s[i+2])
			j++
			i += 3
		default:
			t[j] = s[i]
			j++
			i++
		}
	}
	return string(t), nil
}

func ishex(c byte) bool {
	switch {
	case '0' <= c && c <= '9':
		return true
	case 'a' <= c && c <= 'f':
		return true
	case 'A' <= c && c <= 'F':
		return true
	}
	return false
}

func unhex(c byte) byte {
	switch {
	case '0' <= c && c <= '9':
		return c - '0'
	case 'a' <= c && c <= 'f':
		return c - 'a' + 10
	case 'A' <= c && c <= 'F':
		return c - 'A' + 10
	}
	return 0
}
<|endoftext|>


<commit_before>/*
Copyright 2016 - 2017 Huawei Technologies Co., Ltd. All rights reserved.

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

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

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

package template

var DockerSystemdTemplate = map[string]string{
	"docker-17.04.0-ce": `
[Unit]
Description=Docker Application Container Engine
Documentation=http://docs.docker.io

[Service]
EnvironmentFile=-/run/flannel/docker
ExecStart=/usr/local/bin/dockerd --log-level=error $DOCKER_NETWORK_OPTIONS --iptables=false --ip-masq=false
ExecReload=/bin/kill -s HUP $MAINPID
Restart=on-failure
RestartSec=5
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
Delegate=yes
KillMode=process

[Install]
WantedBy=multi-user.target
`,
	"docker-18.06.0-ce": `
[Unit]
Description=Docker Application Container Engine
Documentation=http://docs.docker.io

[Service]
EnvironmentFile=-/run/flannel/docker
ExecStart=/usr/local/bin/dockerd --log-level=error $DOCKER_NETWORK_OPTIONS --iptables=false --ip-masq=false
ExecReload=/bin/kill -s HUP $MAINPID
Restart=on-failure
RestartSec=5
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
Delegate=yes
KillMode=process

[Install]
WantedBy=multi-user.target
`,
}
<commit_msg>Add template for docker 18.06.1-ce<commit_after>/*
Copyright 2016 - 2017 Huawei Technologies Co., Ltd. All rights reserved.

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

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

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

package template

var DockerSystemdTemplate = map[string]string{
	"docker-17.04.0-ce": `
[Unit]
Description=Docker Application Container Engine
Documentation=http://docs.docker.io

[Service]
EnvironmentFile=-/run/flannel/docker
ExecStart=/usr/local/bin/dockerd --log-level=error $DOCKER_NETWORK_OPTIONS --iptables=false --ip-masq=false
ExecReload=/bin/kill -s HUP $MAINPID
Restart=on-failure
RestartSec=5
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
Delegate=yes
KillMode=process

[Install]
WantedBy=multi-user.target
`,
	"docker-18.06.0-ce": `
[Unit]
Description=Docker Application Container Engine
Documentation=http://docs.docker.io

[Service]
EnvironmentFile=-/run/flannel/docker
ExecStart=/usr/local/bin/dockerd --log-level=error $DOCKER_NETWORK_OPTIONS --iptables=false --ip-masq=false
ExecReload=/bin/kill -s HUP $MAINPID
Restart=on-failure
RestartSec=5
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
Delegate=yes
KillMode=process

[Install]
WantedBy=multi-user.target
`,
	"docker-18.06.1-ce": `
[Unit]
Description=Docker Application Container Engine
Documentation=http://docs.docker.io

[Service]
EnvironmentFile=-/run/flannel/docker
ExecStart=/usr/local/bin/dockerd --log-level=error $DOCKER_NETWORK_OPTIONS --iptables=false --ip-masq=false
ExecReload=/bin/kill -s HUP $MAINPID
Restart=on-failure
RestartSec=5
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
Delegate=yes
KillMode=process

[Install]
WantedBy=multi-user.target
`,
}
<|endoftext|>


<commit_before>package provider

import (
	"fmt"
	"os"
	"strings"
	"time"

	docker "github.com/fsouza/go-dockerclient"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceDockerImage() *schema.Resource {
	return &schema.Resource{
		Create: resourceDockerImageCreate,
		Read:   resourceDockerImageRead,
		Update: resourceDockerImageUpdate,
		Delete: resourceDockerImageDelete,
		Exists: resourceDockerImageExists,

		Schema: map[string]*schema.Schema{
			"registry": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"tag": {
				Type:     schema.TypeString,
				Default:  "latest",
				Required: true,
				ForceNew: true,
			},

			"build_local_path": {
				Type:          schema.TypeString,
				Optional:      true,
				ForceNew:      true,
				ConflictsWith: []string{"build_remote_path", "load_path", "pull"},
			},

			"build_remote_path": {
				Type:          schema.TypeString,
				Optional:      true,
				ForceNew:      true,
				ConflictsWith: []string{"build_local_path", "load_path", "pull"},
			},

			"load_path": {
				Type:          schema.TypeString,
				Optional:      true,
				ForceNew:      true,
				ConflictsWith: []string{"build_local_path", "build_remote_path", "pull"},
			},

			"pull": {
				Type:          schema.TypeBool,
				Optional:      true,
				ForceNew:      true,
				ConflictsWith: []string{"build_local_path", "build_remote_path", "load_path"},
			},

			"keep": {
				Type:     schema.TypeBool,
				Optional: true,
			},

			"push": {
				Type:     schema.TypeBool,
				Optional: true,
			},

			"nocache": {
				Type:     schema.TypeBool,
				Optional: true,
			},

			"dockerfile": {
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"id": {
				Type:     schema.TypeString,
				Computed: true,
				ForceNew: true,
			},

			"created_at": {
				Type:     schema.TypeInt,
				Computed: true,
				ForceNew: true,
			},

			"docker_version": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"comment": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"author": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"os": {
				Type:     schema.TypeString,
				Computed: true,
				ForceNew: true,
			},

			"architecture": {
				Type:     schema.TypeString,
				Computed: true,
				ForceNew: true,
			},

			"size": {
				Type:     schema.TypeInt,
				Computed: true,
			},

			"virtual_size": {
				Type:     schema.TypeInt,
				Computed: true,
			},

			"parent": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"digests": {
				Type:     schema.TypeList,
				Elem:     schema.TypeString,
				Computed: true,
				ForceNew: true,
			},

			"all_tags": {
				Type:     schema.TypeList,
				Elem:     schema.TypeString,
				Computed: true,
			},

			"labels": {
				Type:     schema.TypeMap,
				Elem:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"memory": {
				Type:     schema.TypeInt,
				Optional: true,
				ForceNew: true,
			},

			"memswap": {
				Type:     schema.TypeInt,
				Optional: true,
				ForceNew: true,
			},

			"cpu_shares": {
				Type:     schema.TypeInt,
				Optional: true,
				ForceNew: true,
			},

			"cpu_quota": {
				Type:     schema.TypeInt,
				Optional: true,
				ForceNew: true,
			},

			"cpu_period": {
				Type:     schema.TypeInt,
				Optional: true,
				ForceNew: true,
			},

			"cpu_set_cpus": {
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"networkmode": {
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"cgroup_parent": {
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"timeout": {
				Type:     schema.TypeInt,
				Optional: true,
			},

			"ulimit_soft": {
				Type:     schema.TypeMap,
				Elem:     schema.TypeInt,
				Optional: true,
				ForceNew: true,
			},

			"ulimit_hard": {
				Type:     schema.TypeMap,
				Elem:     schema.TypeInt,
				Optional: true,
				ForceNew: true,
			},

			"build_args": {
				Type:     schema.TypeMap,
				Elem:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"auth": {
				Type:      schema.TypeMap,
				Elem:      schema.TypeString,
				Optional:  true,
				Sensitive: true,
			},
		},
	}
}

func resourceDockerImageCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*docker.Client)
	authConfig, err := getAuthConfig(d)
	if err != nil {
		return err
	}

	switch {
	case d.Get("pull").(bool):
		err := client.PullImage(docker.PullImageOptions{
			Repository:        strings.Join([]string{d.Get("registry").(string), d.Get("name").(string)}, ":"),
			Tag:               d.Get("tag").(string),
			InactivityTimeout: time.Duration(d.Get("timeout").(int64)) * time.Second,
		}, authConfig[d.Get("registry").(string)])
		if err != nil {
			return err
		}
	case d.Get("load_path").(string) != "":
		fh, err := os.OpenFile(d.Get("load_path").(string), os.O_RDONLY, 0600)
		if err != nil {
			return err
		}
		defer fh.Close()
		err = client.LoadImage(docker.LoadImageOptions{
			InputStream: fh,
		})
		if err != nil {
			return err
		}
	case d.Get("build_local_path").(string) != "" || d.Get("build_remote_path").(string) != "":
		ulimitMap := make(map[string]*docker.ULimit)
		for ulimitName, ulimitSoft := range d.Get("ulimit_soft").(map[string]int64) {
			ulimit, ok := ulimitMap[ulimitName]
			if !ok {
				ulimit = &docker.ULimit{Name: ulimitName}
				ulimitMap[ulimitName] = ulimit
			}
			ulimit.Soft = ulimitSoft
		}
		for ulimitName, ulimitHard := range d.Get("ulimit_hard").(map[string]int64) {
			ulimit, ok := ulimitMap[ulimitName]
			if !ok {
				ulimit = &docker.ULimit{Name: ulimitName}
				ulimitMap[ulimitName] = ulimit
			}
			ulimit.Hard = ulimitHard
		}
		var ulimitList []docker.ULimit
		for _, ulimit := range ulimitMap {
			ulimitList = append(ulimitList, *ulimit)
		}
		var buildArgList []docker.BuildArg
		for k, v := range d.Get("build_args").(map[string]string) {
			buildArgList = append(buildArgList, docker.BuildArg{
				Name:  k,
				Value: v,
			})
		}
		imageName := strings.Join([]string{d.Get("name").(string), d.Get("tag").(string)}, ":")
		if d.Get("registry").(string) != "" {
			imageName = strings.Join([]string{d.Get("registry").(string), imageName}, ":")
		}
		err := client.BuildImage(docker.BuildImageOptions{
			Name:              imageName,
			Dockerfile:        d.Get("dockerfile").(string),
			SuppressOutput:    true,
			NoCache:           d.Get("nocache").(bool),
			Pull:              d.Get("pull").(bool),
			Memory:            d.Get("memory").(int64),
			Memswap:           d.Get("memswap").(int64),
			CPUShares:         d.Get("cpushares").(int64),
			CPUQuota:          d.Get("cpuquota").(int64),
			CPUPeriod:         d.Get("cpuperiod").(int64),
			CPUSetCPUs:        d.Get("cpusetcpus").(string),
			NetworkMode:       d.Get("networkmode").(string),
			CgroupParent:      d.Get("cgroupparent").(string),
			InactivityTimeout: time.Duration(d.Get("timeout").(int64)) * time.Second,
			Labels:            d.Get("labels").(map[string]string),
			Remote:            d.Get("build_remote_path").(string),
			ContextDir:        d.Get("build_local_path").(string),
			AuthConfigs: docker.AuthConfigurations{
				Configs: authConfig,
			},
			Ulimits:   ulimitList,
			BuildArgs: buildArgList,
		})
		if err != nil {
			return err
		}
	}

	if d.Get("push").(bool) {
		err := client.PushImage(docker.PushImageOptions{
			Name:              d.Get("name").(string),
			Registry:          d.Get("registry").(string),
			Tag:               d.Get("tag").(string),
			InactivityTimeout: time.Duration(d.Get("timeout").(int64)) * time.Second,
		}, authConfig[d.Get("registry").(string)])
		if err != nil {
			return err
		}
	}

	return resourceDockerImageRead(d, meta)
}

func resourceDockerImageRead(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*docker.Client)

	imageName := strings.Join([]string{d.Get("name").(string), d.Get("tag").(string)}, ":")
	if d.Get("registry").(string) != "" {
		imageName = strings.Join([]string{d.Get("registry").(string), imageName}, ":")
	}

	image, err := client.InspectImage(imageName)
	if err != nil {
		return err
	}
	d.Set("id", image.ID)
	d.Set("parent", image.Parent)
	d.Set("comment", image.Comment)
	d.Set("docker_version", image.DockerVersion)
	d.Set("author", image.Author)
	d.Set("architecture", image.Architecture)
	d.Set("size", image.Size)
	d.Set("virtual_size", image.VirtualSize)
	d.Set("os", image.OS)
	d.Set("created_at", image.Created.Unix())
	d.Set("labels", image.Config.Labels)
	d.Set("digests", image.RepoDigests)
	d.Set("all_tags", image.RepoTags)
	return nil
}

func getAuthConfig(d *schema.ResourceData) (map[string]docker.AuthConfiguration, error) {
	authConfig := make(map[string]docker.AuthConfiguration)
	authData := d.Get("auth").(map[string]string)
	for authAddress, authPassword := range authData {
		p := strings.SplitN(authAddress, "@", 2)
		if len(p) < 2 {
			return nil, fmt.Errorf("Invalid value for field \"auth\"")
		}
		authHostname, authUsername := p[1], p[0]
		authConfig[authHostname] = docker.AuthConfiguration{
			Username:      authUsername,
			Password:      authPassword,
			ServerAddress: authHostname,
		}
	}
	return authConfig, nil
}

func resourceDockerImageUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*docker.Client)

	authConfig, err := getAuthConfig(d)
	if err != nil {
		return err
	}

	if d.HasChange("push") && d.Get("push").(bool) {
		err := client.PushImage(docker.PushImageOptions{
			Name:              d.Get("name").(string),
			Registry:          d.Get("registry").(string),
			Tag:               d.Get("tag").(string),
			InactivityTimeout: time.Duration(d.Get("timeout").(int64)) * time.Second,
		}, authConfig[d.Get("registry").(string)])
		if err != nil {
			return err
		}
	}
	return nil
}

func resourceDockerImageDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*docker.Client)

	if d.Get("keep").(bool) {
		return nil
	}

	imageName := strings.Join([]string{d.Get("name").(string), d.Get("tag").(string)}, ":")
	if d.Get("registry").(string) != "" {
		imageName = strings.Join([]string{d.Get("registry").(string), imageName}, ":")
	}

	return client.RemoveImageExtended(imageName, docker.RemoveImageOptions{
		Force: true,
	})
}

func resourceDockerImageExists(d *schema.ResourceData, meta interface{}) (bool, error) {
	client := meta.(*docker.Client)

	imageName := strings.Join([]string{d.Get("name").(string), d.Get("tag").(string)}, ":")
	if d.Get("registry").(string) != "" {
		imageName = strings.Join([]string{d.Get("registry").(string), imageName}, ":")
	}

	_, err := client.InspectImage(imageName)
	switch err {
	case nil:
		return true, nil
	case docker.ErrNoSuchImage:
		return false, nil
	default:
		return false, err
	}
}
<commit_msg>Fixes to repository name generation. Changed tag option from Required to Optional.<commit_after>package provider

import (
	"fmt"
	"os"
	"strings"
	"time"

	docker "github.com/fsouza/go-dockerclient"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceDockerImage() *schema.Resource {
	return &schema.Resource{
		Create: resourceDockerImageCreate,
		Read:   resourceDockerImageRead,
		Update: resourceDockerImageUpdate,
		Delete: resourceDockerImageDelete,
		Exists: resourceDockerImageExists,

		Schema: map[string]*schema.Schema{
			"registry": {
				Type:     schema.TypeString,
				Required: false,
				ForceNew: true,
			},

			"name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"tag": {
				Type:     schema.TypeString,
				Default:  "latest",
                                Optional: true,
				ForceNew: true,
			},

			"build_local_path": {
				Type:          schema.TypeString,
				Optional:      true,
				ForceNew:      true,
				ConflictsWith: []string{"build_remote_path", "load_path", "pull"},
			},

			"build_remote_path": {
				Type:          schema.TypeString,
				Optional:      true,
				ForceNew:      true,
				ConflictsWith: []string{"build_local_path", "load_path", "pull"},
			},

			"load_path": {
				Type:          schema.TypeString,
				Optional:      true,
				ForceNew:      true,
				ConflictsWith: []string{"build_local_path", "build_remote_path", "pull"},
			},

			"pull": {
				Type:          schema.TypeBool,
				Optional:      true,
				ForceNew:      true,
				ConflictsWith: []string{"build_local_path", "build_remote_path", "load_path"},
			},

			"keep": {
				Type:     schema.TypeBool,
				Optional: true,
			},

			"push": {
				Type:     schema.TypeBool,
				Optional: true,
			},

			"nocache": {
				Type:     schema.TypeBool,
				Optional: true,
			},

			"dockerfile": {
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"id": {
				Type:     schema.TypeString,
				Computed: true,
				ForceNew: true,
			},

			"created_at": {
				Type:     schema.TypeInt,
				Computed: true,
				ForceNew: true,
			},

			"docker_version": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"comment": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"author": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"os": {
				Type:     schema.TypeString,
				Computed: true,
				ForceNew: true,
			},

			"architecture": {
				Type:     schema.TypeString,
				Computed: true,
				ForceNew: true,
			},

			"size": {
				Type:     schema.TypeInt,
				Computed: true,
			},

			"virtual_size": {
				Type:     schema.TypeInt,
				Computed: true,
			},

			"parent": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"digests": {
				Type:     schema.TypeList,
				Elem:     schema.TypeString,
				Computed: true,
				ForceNew: true,
			},

			"all_tags": {
				Type:     schema.TypeList,
				Elem:     schema.TypeString,
				Computed: true,
			},

			"labels": {
				Type:     schema.TypeMap,
				Elem:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"memory": {
				Type:     schema.TypeInt,
				Optional: true,
				ForceNew: true,
			},

			"memswap": {
				Type:     schema.TypeInt,
				Optional: true,
				ForceNew: true,
			},

			"cpu_shares": {
				Type:     schema.TypeInt,
				Optional: true,
				ForceNew: true,
			},

			"cpu_quota": {
				Type:     schema.TypeInt,
				Optional: true,
				ForceNew: true,
			},

			"cpu_period": {
				Type:     schema.TypeInt,
				Optional: true,
				ForceNew: true,
			},

			"cpu_set_cpus": {
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"networkmode": {
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"cgroup_parent": {
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"timeout": {
				Type:     schema.TypeInt,
				Optional: true,
			},

			"ulimit_soft": {
				Type:     schema.TypeMap,
				Elem:     schema.TypeInt,
				Optional: true,
				ForceNew: true,
			},

			"ulimit_hard": {
				Type:     schema.TypeMap,
				Elem:     schema.TypeInt,
				Optional: true,
				ForceNew: true,
			},

			"build_args": {
				Type:     schema.TypeMap,
				Elem:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"auth": {
				Type:      schema.TypeMap,
				Elem:      schema.TypeString,
				Optional:  true,
				Sensitive: true,
			},
		},
	}
}

func resourceDockerImageCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*docker.Client)
	authConfig, err := getAuthConfig(d)
	if err != nil {
		return err
	}

	repoName := d.Get("name").(string)
	if d.Get("registry").(string) != "" {
		repoName = strings.Join([]string{d.Get("registry").(string), repoName}, "/")
	}

	switch {
	case d.Get("pull").(bool):
		err := client.PullImage(docker.PullImageOptions{
			Repository:        repoName,
			Tag:               d.Get("tag").(string),
			InactivityTimeout: time.Duration(d.Get("timeout").(int64)) * time.Second,
		}, authConfig[d.Get("registry").(string)])
		if err != nil {
			return err
		}
	case d.Get("load_path").(string) != "":
		fh, err := os.OpenFile(d.Get("load_path").(string), os.O_RDONLY, 0600)
		if err != nil {
			return err
		}
		defer fh.Close()
		err = client.LoadImage(docker.LoadImageOptions{
			InputStream: fh,
		})
		if err != nil {
			return err
		}
	case d.Get("build_local_path").(string) != "" || d.Get("build_remote_path").(string) != "":
		ulimitMap := make(map[string]*docker.ULimit)
		for ulimitName, ulimitSoft := range d.Get("ulimit_soft").(map[string]int64) {
			ulimit, ok := ulimitMap[ulimitName]
			if !ok {
				ulimit = &docker.ULimit{Name: ulimitName}
				ulimitMap[ulimitName] = ulimit
			}
			ulimit.Soft = ulimitSoft
		}
		for ulimitName, ulimitHard := range d.Get("ulimit_hard").(map[string]int64) {
			ulimit, ok := ulimitMap[ulimitName]
			if !ok {
				ulimit = &docker.ULimit{Name: ulimitName}
				ulimitMap[ulimitName] = ulimit
			}
			ulimit.Hard = ulimitHard
		}
		var ulimitList []docker.ULimit
		for _, ulimit := range ulimitMap {
			ulimitList = append(ulimitList, *ulimit)
		}
		var buildArgList []docker.BuildArg
		for k, v := range d.Get("build_args").(map[string]string) {
			buildArgList = append(buildArgList, docker.BuildArg{
				Name:  k,
				Value: v,
			})
		}
		imageName := strings.Join([]string{d.Get("name").(string), d.Get("tag").(string)}, ":")
		if d.Get("registry").(string) != "" {
			imageName = strings.Join([]string{d.Get("registry").(string), imageName}, "/")
		}
		err := client.BuildImage(docker.BuildImageOptions{
			Name:              imageName,
			Dockerfile:        d.Get("dockerfile").(string),
			SuppressOutput:    true,
			NoCache:           d.Get("nocache").(bool),
			Pull:              d.Get("pull").(bool),
			Memory:            d.Get("memory").(int64),
			Memswap:           d.Get("memswap").(int64),
			CPUShares:         d.Get("cpushares").(int64),
			CPUQuota:          d.Get("cpuquota").(int64),
			CPUPeriod:         d.Get("cpuperiod").(int64),
			CPUSetCPUs:        d.Get("cpusetcpus").(string),
			NetworkMode:       d.Get("networkmode").(string),
			CgroupParent:      d.Get("cgroupparent").(string),
			InactivityTimeout: time.Duration(d.Get("timeout").(int64)) * time.Second,
			Labels:            d.Get("labels").(map[string]string),
			Remote:            d.Get("build_remote_path").(string),
			ContextDir:        d.Get("build_local_path").(string),
			AuthConfigs: docker.AuthConfigurations{
				Configs: authConfig,
			},
			Ulimits:   ulimitList,
			BuildArgs: buildArgList,
		})
		if err != nil {
			return err
		}
	}

	if d.Get("push").(bool) {
		err := client.PushImage(docker.PushImageOptions{
			Name:              d.Get("name").(string),
			Registry:          d.Get("registry").(string),
			Tag:               d.Get("tag").(string),
			InactivityTimeout: time.Duration(d.Get("timeout").(int64)) * time.Second,
		}, authConfig[d.Get("registry").(string)])
		if err != nil {
			return err
		}
	}

	return resourceDockerImageRead(d, meta)
}

func resourceDockerImageRead(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*docker.Client)

	imageName := strings.Join([]string{d.Get("name").(string), d.Get("tag").(string)}, ":")
	if d.Get("registry").(string) != "" {
		imageName = strings.Join([]string{d.Get("registry").(string), imageName}, "/")
	}

	image, err := client.InspectImage(imageName)
	if err != nil {
		return err
	}
	d.Set("id", image.ID)
	d.Set("parent", image.Parent)
	d.Set("comment", image.Comment)
	d.Set("docker_version", image.DockerVersion)
	d.Set("author", image.Author)
	d.Set("architecture", image.Architecture)
	d.Set("size", image.Size)
	d.Set("virtual_size", image.VirtualSize)
	d.Set("os", image.OS)
	d.Set("created_at", image.Created.Unix())
	d.Set("labels", image.Config.Labels)
	d.Set("digests", image.RepoDigests)
	d.Set("all_tags", image.RepoTags)
	return nil
}

func getAuthConfig(d *schema.ResourceData) (map[string]docker.AuthConfiguration, error) {
	authConfig := make(map[string]docker.AuthConfiguration)
	authData := d.Get("auth").(map[string]string)
	for authAddress, authPassword := range authData {
		p := strings.SplitN(authAddress, "@", 2)
		if len(p) < 2 {
			return nil, fmt.Errorf("Invalid value for field \"auth\"")
		}
		authHostname, authUsername := p[1], p[0]
		authConfig[authHostname] = docker.AuthConfiguration{
			Username:      authUsername,
			Password:      authPassword,
			ServerAddress: authHostname,
		}
	}
	return authConfig, nil
}

func resourceDockerImageUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*docker.Client)

	authConfig, err := getAuthConfig(d)
	if err != nil {
		return err
	}

	if d.HasChange("push") && d.Get("push").(bool) {
		err := client.PushImage(docker.PushImageOptions{
			Name:              d.Get("name").(string),
			Registry:          d.Get("registry").(string),
			Tag:               d.Get("tag").(string),
			InactivityTimeout: time.Duration(d.Get("timeout").(int64)) * time.Second,
		}, authConfig[d.Get("registry").(string)])
		if err != nil {
			return err
		}
	}
	return nil
}

func resourceDockerImageDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*docker.Client)

	if d.Get("keep").(bool) {
		return nil
	}

	imageName := strings.Join([]string{d.Get("name").(string), d.Get("tag").(string)}, ":")
	if d.Get("registry").(string) != "" {
		imageName = strings.Join([]string{d.Get("registry").(string), imageName}, "/")
	}

	return client.RemoveImageExtended(imageName, docker.RemoveImageOptions{
		Force: true,
	})
}

func resourceDockerImageExists(d *schema.ResourceData, meta interface{}) (bool, error) {
	client := meta.(*docker.Client)

	imageName := strings.Join([]string{d.Get("name").(string), d.Get("tag").(string)}, ":")
	if d.Get("registry").(string) != "" {
		imageName = strings.Join([]string{d.Get("registry").(string), imageName}, "/")
	}

	_, err := client.InspectImage(imageName)
	switch err {
	case nil:
		return true, nil
	case docker.ErrNoSuchImage:
		return false, nil
	default:
		return false, err
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2017 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 kube

import (
	"github.com/prometheus/client_golang/prometheus"

	prowapi "k8s.io/test-infra/prow/apis/prowjobs/v1"
)

var (
	prowJobs = prometheus.NewGaugeVec(prometheus.GaugeOpts{
		Name: "prowjobs",
		Help: "Number of prowjobs in the system",
	}, []string{
		// name of the job
		"job_name",
		// type of the prowjob: presubmit, postsubmit, periodic, batch
		"type",
		// state of the prowjob: triggered, pending, success, failure, aborted, error
		"state",
		// the org of the prowjob's repo
		"org",
		// the prowjob's repo
		"repo",
		// the base_ref of the prowjob's repo
		"base_ref",
	})
)

type jobLabel struct {
	jobName string
	jobType string
	state   string
	org     string
	repo    string
	baseRef string
}

func init() {
	prometheus.MustRegister(prowJobs)
}

func getJobLabelMap(pjs []prowapi.ProwJob) map[jobLabel]float64 {
	jobLabelMap := make(map[jobLabel]float64)

	for _, pj := range pjs {
		jl := jobLabel{jobName: pj.Spec.Job, jobType: string(pj.Spec.Type), state: string(pj.Status.State)}

		if pj.Spec.Refs != nil {
			jl.org = pj.Spec.Refs.Org
			jl.repo = pj.Spec.Refs.Repo
			jl.baseRef = pj.Spec.Refs.BaseRef
		} else if len(pj.Spec.ExtraRefs) > 0 {
			jl.org = pj.Spec.ExtraRefs[0].Org
			jl.repo = pj.Spec.ExtraRefs[0].Repo
			jl.baseRef = pj.Spec.ExtraRefs[0].BaseRef
		}

		jobLabelMap[jl]++
	}
	return jobLabelMap
}

// GatherProwJobMetrics gathers prometheus metrics for prowjobs.
func GatherProwJobMetrics(pjs []prowapi.ProwJob) {

	jobLabelMap := getJobLabelMap(pjs)
	// This may be racing with the prometheus server but we need to remove
	// stale metrics like triggered or pending jobs that are now complete.
	prowJobs.Reset()

	for jl, count := range jobLabelMap {
		prowJobs.WithLabelValues(jl.jobName, jl.jobType, jl.state, jl.org, jl.repo, jl.baseRef).Set(count)
	}
}
<commit_msg>Record ProwJob state transitions in metrics<commit_after>/*
Copyright 2017 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 kube

import (
	"github.com/prometheus/client_golang/prometheus"

	prowapi "k8s.io/test-infra/prow/apis/prowjobs/v1"
)

var (
	metricLabels = []string{
		// name of the job
		"job_name",
		// type of the prowjob: presubmit, postsubmit, periodic, batch
		"type",
		// state of the prowjob: triggered, pending, success, failure, aborted, error
		"state",
		// the org of the prowjob's repo
		"org",
		// the prowjob's repo
		"repo",
		// the base_ref of the prowjob's repo
		"base_ref",
	}
	prowJobs = prometheus.NewGaugeVec(prometheus.GaugeOpts{
		Name: "prowjobs",
		Help: "Number of prowjobs in the system",
	}, metricLabels)
	prowJobTransitions = prometheus.NewCounterVec(prometheus.CounterOpts{
		Name: "prowjob_state_transitions",
		Help: "Number of prowjobs transitioning states",
	}, metricLabels)
)

type jobLabel struct {
	jobName string
	jobType string
	state   string
	org     string
	repo    string
	baseRef string
}

func (jl *jobLabel) values() []string {
	return []string{jl.jobName, jl.jobType, jl.state, jl.org, jl.repo, jl.baseRef}
}

func init() {
	prometheus.MustRegister(prowJobs)
}

func getJobLabelMap(pjs []prowapi.ProwJob) map[jobLabel]float64 {
	jobLabelMap := make(map[jobLabel]float64)

	for _, pj := range pjs {
		jl := jobLabel{jobName: pj.Spec.Job, jobType: string(pj.Spec.Type), state: string(pj.Status.State)}

		if pj.Spec.Refs != nil {
			jl.org = pj.Spec.Refs.Org
			jl.repo = pj.Spec.Refs.Repo
			jl.baseRef = pj.Spec.Refs.BaseRef
		} else if len(pj.Spec.ExtraRefs) > 0 {
			jl.org = pj.Spec.ExtraRefs[0].Org
			jl.repo = pj.Spec.ExtraRefs[0].Repo
			jl.baseRef = pj.Spec.ExtraRefs[0].BaseRef
		}

		jobLabelMap[jl]++
	}
	return jobLabelMap
}

// previousStates records the prowJobs we were called with previously
var previousStates map[jobLabel]prowapi.ProwJobState

// GatherProwJobMetrics gathers prometheus metrics for prowjobs.
// Not threadsafe, ensure this is called serially.
func GatherProwJobMetrics(current []prowapi.ProwJob) {

	// record the current state of ProwJob CRs on the system
	jobLabelMap := getJobLabelMap(current)
	// This may be racing with the prometheus server but we need to remove
	// stale metrics like triggered or pending jobs that are now complete.
	prowJobs.Reset()

	for jl, count := range jobLabelMap {
		prowJobs.WithLabelValues(jl.values()...).Set(count)
	}

	// record state transitions since the last time we were called
	currentStates := map[jobLabel]prowapi.ProwJobState{}
	for jl := range jobLabelMap {
		state := prowapi.ProwJobState(jl.state)
		currentStates[jl] = state

		if previousState, seen := previousStates[jl]; !seen || previousState != state {
			prowJobTransitions.WithLabelValues(jl.values()...).Inc()
		}
	}

	previousStates = currentStates
}
<|endoftext|>


<commit_before>// Copyright 2011 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 oglemock_test

import (
	. "github.com/jacobsa/ogletest"
)

////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////

type ControllerTest struct {
}

func init() { RegisterTestSuite(&ControllerTest{}) }

////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////

func (t *ControllerTest) DoesFoo() {
}
<commit_msg>Added a bunch of test names.<commit_after>// Copyright 2011 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 oglemock_test

import (
	. "github.com/jacobsa/ogletest"
)

////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////

type ControllerTest struct {
}

func init() { RegisterTestSuite(&ControllerTest{}) }

////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////

func (t *ControllerTest) FinishWithoutAnyEvents() {
}

func (t *ControllerTest) HandleCallForUnknownObject() {
}

func (t *ControllerTest) ExpectCallForUnknownMethod() {
}

func (t *ControllerTest) PartialExpectationGivenWrongNumberOfArgs() {
}

func (t *ControllerTest) PartialExpectationCalledTwice() {
}

func (t *ControllerTest) ExpectThenNonMatchingCall() {
}

func (t *ControllerTest) ExplicitCardinalityNotSatisfied() {
}

func (t *ControllerTest) ImplicitOneTimeActionCountNotSatisfied() {
}

func (t *ControllerTest) ImplicitOneTimeActionLowerBoundNotSatisfied() {
}

func (t *ControllerTest) ImplicitCardinalityOfOneNotSatisfied() {
}

func (t *ControllerTest) ExplicitCardinalitySatisfied() {
}

func (t *ControllerTest) ImplicitOneTimeActionCountSatisfied() {
}

func (t *ControllerTest) ImplicitOneTimeActionLowerBoundSatisfied() {
}

func (t *ControllerTest) FallbackActionConfiguredWithZeroCalls() {
}

func (t *ControllerTest) FallbackActionConfiguredWithMultipleCalls() {
}

func (t *ControllerTest) ImplicitCardinalityOfOneSatisfied() {
}

func (t *ControllerTest) InvokesOneTimeActions() {
}

func (t *ControllerTest) InvokesFallbackActions() {
}

func (t *ControllerTest) InvokesImplicitActions() {
}
<|endoftext|>


<commit_before>package endpoints

import (
	"encoding/json"
	"fmt"
	"net/http"
	"respond"
	"respond/middleware"
)

type JSONEndpoint struct {
	handler Handler
}

func emptyJsonHandler(respond http.ResponseWriter, request *http.Request) (interface{}, error) {
	return (map[string]interface{}{}), nil
}

func NewJSONEndpoint() *JSONEndpoint {

	ep := &JSONEndpoint{}
	ep.Handler(emptyJsonHandler)

	return ep
}

func (endpoint *JSONEndpoint) Handler(fn Handler) *JSONEndpoint {
	endpoint.handler = fn
	return endpoint
}

func (endpoint *JSONEndpoint) Middlewares() []middleware.Middleware {
	return []middleware.Middleware{respond.NewAcceptFilterMiddleware(`application/json`)}
}

func (endpoint *JSONEndpoint) Process(response http.ResponseWriter, request *http.Request) (returnError error) {

	defer func() {

		if err := recover(); err != nil {
			returnError = fmt.Errorf("json endpoint: render failed: %s", err)
		}
	}()

	data, err := endpoint.handler(response, request)

	if err != nil {
		panic(err)
	}

	var payload []byte

	if payload, err = json.Marshal(data); err != nil {
		panic(err)
	}

	if _, err = response.Write(payload); err != nil {
		panic(err)
	}

	response.Header().Add(`Content-Type`, `application/json`)

	return nil
}
<commit_msg>json endpoint can have a handler that returns []byte which is data already encoded as JSON<commit_after>package endpoints

import (
	"encoding/json"
	"fmt"
	"net/http"
	"respond"
	"respond/middleware"
)

type JSONHandler func(http.ResponseWriter, *http.Request) ([]byte, error)

type JSONEndpoint struct {
	handler JSONHandler
}

func emptyJsonHandler(respond http.ResponseWriter, request *http.Request) (interface{}, error) {

	return (map[string]interface{}{}), nil
}

func NewJSONEndpoint() *JSONEndpoint {

	ep := &JSONEndpoint{}
	ep.Handler(emptyJsonHandler)

	return ep
}

func (endpoint *JSONEndpoint) Handler(fn Handler) *JSONEndpoint {

	return endpoint.JSONHandler(func (response http.ResponseWriter, request *http.Request) ([]byte, error) {

		data, err := fn(response, request)

		if err != nil {
			return nil, err
		}

		var payload []byte

		if payload, err = json.Marshal(data); err != nil {
			return nil, err
		}

		return payload, err
	})
}

func (endpoint *JSONEndpoint) JSONHandler(fn JSONHandler) *JSONEndpoint {
	endpoint.handler = fn
	return endpoint
}

func (endpoint *JSONEndpoint) Middlewares() []middleware.Middleware {
	return []middleware.Middleware{respond.NewAcceptFilterMiddleware(`application/json`)}
}

func (endpoint *JSONEndpoint) Process(response http.ResponseWriter, request *http.Request) (returnError error) {

	defer func() {

		if err := recover(); err != nil {
			returnError = fmt.Errorf("json endpoint: render failed: %s", err)
		}
	}()

	payload, err := endpoint.handler(response, request)

	if err != nil {
		panic(err)
	}

	if _, err = response.Write(payload); err != nil {
		panic(err)
	}

	response.Header().Add(`Content-Type`, `application/json`)

	return nil
}
<|endoftext|>


<commit_before>// MIT License

// Copyright (c) 2017 FLYING

// 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 decorates

import (
	"github.com/yang-f/beauty/db"
	"github.com/yang-f/beauty/models"
	"github.com/yang-f/beauty/utils/log"
	"github.com/yang-f/beauty/utils/token"
	"net/http"
	"strings"
)

func (inner Handler) Auth() Handler {
	return Handler(func(w http.ResponseWriter, r *http.Request) *models.APPError {
		tokenString := ""
		if r.Header != nil {
			if authorization := r.Header["Authorization"]; len(authorization) > 0 {
				tokenString = authorization[0]
			}
		}
		if tokenString == "" {
			cookie, err := r.Cookie("token")
			if err != nil {
				return &models.APPError{err, "token not found.", "AUTH_FAILED", 403}
			}
			tokenString = cookie.Value
		}
		key, err := token.Valid(tokenString)
		if err != nil {
			return &models.APPError{err, "bad token.", "AUTH_FAILED", 403}
		}
		if !strings.Contains(key, "|") {
			return &models.APPError{err, "user not found.", "NOT_FOUND", 404}
		}
		keys := strings.Split(key, "|")
		rows, _, err := db.QueryNonLogging("select * from user where user_id = '%v' and user_pass = '%v'", keys[0], keys[1])
		if err != nil {
			return &models.APPError{err, "can not connect database.", "DB_ERROR", 500}
		}
		if len(rows) == 0 {
			return &models.APPError{err, "user not found.", "NOT_FOUND", 404}
		}
		go log.Printf("user_id:%v", keys[0])
		inner.ServeHTTP(w, r)
		return nil
	})
}
<commit_msg>fix auth bug<commit_after>// MIT License

// Copyright (c) 2017 FLYING

// 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 decorates

import (
	"github.com/yang-f/beauty/db"
	"github.com/yang-f/beauty/models"
	"github.com/yang-f/beauty/utils/log"
	"github.com/yang-f/beauty/utils/token"
	"net/http"
	"strings"
)

func (inner Handler) Auth() Handler {
	return Handler(func(w http.ResponseWriter, r *http.Request) *models.APPError {
		tokenString := ""
		cookie, _ := r.Cookie("token")
		if cookie != nil {
			tokenString = cookie.Value
		}
		if tokenString == "" {
			if r.Header != nil {
				if authorization := r.Header["Authorization"]; len(authorization) > 0 {
					tokenString = authorization[0]
				}
			}
		}
		key, err := token.Valid(tokenString)
		if err != nil {
			return &models.APPError{err, "bad token.", "AUTH_FAILED", 403}
		}
		if !strings.Contains(key, "|") {
			return &models.APPError{err, "user not found.", "NOT_FOUND", 404}
		}
		keys := strings.Split(key, "|")
		rows, _, err := db.QueryNonLogging("select * from user where user_id = '%v' and user_pass = '%v'", keys[0], keys[1])
		if err != nil {
			return &models.APPError{err, "can not connect database.", "DB_ERROR", 500}
		}
		if len(rows) == 0 {
			return &models.APPError{err, "user not found.", "NOT_FOUND", 404}
		}
		go log.Printf("user_id:%v", keys[0])
		inner.ServeHTTP(w, r)
		return nil
	})
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
	"github.com/sirupsen/logrus"
)

const VERSION = "0.0.231"

func main() {
	// XXX (reed): normalize
	level, err := logrus.ParseLevel(os.Getenv("LOG_LEVEL"))
	if err != nil {
		level = logrus.InfoLevel
	}
	logrus.SetLevel(level)

	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.198", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory; use k8s for kuberneted")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.StringVar(&conf.MgmtListen, "mgmt-listen", ":8081", "management port to run on")
	flag.IntVar(&conf.ShutdownTimeout, "shutdown-timeout", 0, "graceful shutdown timeout")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckHealthy, "hc-healthy", 1, "threshold of success checks to declare node healthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.StringVar(&conf.Namespace, "namespace", "", "kubernetes namespace to monitor")
	flag.StringVar(&conf.LabelSelector, "label-selector", "", "kubernetes label selector to monitor")
	flag.IntVar(&conf.TargetPort, "target-port", 8080, "kubernetes port to target on selected pods")

	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	db, err := lb.NewDB(conf) // Handles case where DBurl == "k8s"
	if err != nil {
		logrus.WithError(err).Fatal("error setting up database")
	}
	defer db.Close()

	g, err := lb.NewAllGrouper(conf, db)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	servers := make([]*http.Server, 0, 1)
	handler := lb.NewProxy(k, g, r, conf)

	// a separate mgmt listener is requested? then let's create a LB traffic only server
	if conf.Listen != conf.MgmtListen {
		servers = append(servers, &http.Server{Addr: conf.Listen, Handler: handler})
		handler = lb.NullHandler()
	}

	// add mgmt endpoints to the handler
	handler = g.Wrap(handler) // add/del/list endpoints
	handler = r.Wrap(handler) // stats / dash endpoint

	servers = append(servers, &http.Server{Addr: conf.MgmtListen, Handler: handler})
	serve(servers, &conf)
}

func serve(servers []*http.Server, conf *lb.Config) {

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)

	for i := 0; i < len(servers); i++ {
		go func(idx int) {
			err := servers[idx].ListenAndServe()
			if err != nil && err != http.ErrServerClosed {
				logrus.WithFields(logrus.Fields{"server_id": idx}).WithError(err).Fatal("server error")
			} else {
				logrus.WithFields(logrus.Fields{"server_id": idx}).Info("server stopped")
			}
		}(i)
	}

	sig := <-ch
	logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")

	for i := 0; i < len(servers); i++ {

		ctx := context.Background()

		if conf.ShutdownTimeout > 0 {
			tmpCtx, cancel := context.WithTimeout(context.Background(), time.Duration(conf.ShutdownTimeout)*time.Second)
			ctx = tmpCtx
			defer cancel()
		}

		err := servers[i].Shutdown(ctx) // safe shutdown
		if err != nil {
			logrus.WithFields(logrus.Fields{"server_id": i}).WithError(err).Fatal("server shutdown error")
		} else {
			logrus.WithFields(logrus.Fields{"server_id": i}).Info("server shutdown")
		}
	}
}
<commit_msg>fnlb: 0.0.232 release [skip ci]<commit_after>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
	"github.com/sirupsen/logrus"
)

const VERSION = "0.0.232"

func main() {
	// XXX (reed): normalize
	level, err := logrus.ParseLevel(os.Getenv("LOG_LEVEL"))
	if err != nil {
		level = logrus.InfoLevel
	}
	logrus.SetLevel(level)

	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.199", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory; use k8s for kuberneted")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.StringVar(&conf.MgmtListen, "mgmt-listen", ":8081", "management port to run on")
	flag.IntVar(&conf.ShutdownTimeout, "shutdown-timeout", 0, "graceful shutdown timeout")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckHealthy, "hc-healthy", 1, "threshold of success checks to declare node healthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.StringVar(&conf.Namespace, "namespace", "", "kubernetes namespace to monitor")
	flag.StringVar(&conf.LabelSelector, "label-selector", "", "kubernetes label selector to monitor")
	flag.IntVar(&conf.TargetPort, "target-port", 8080, "kubernetes port to target on selected pods")

	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	db, err := lb.NewDB(conf) // Handles case where DBurl == "k8s"
	if err != nil {
		logrus.WithError(err).Fatal("error setting up database")
	}
	defer db.Close()

	g, err := lb.NewAllGrouper(conf, db)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	servers := make([]*http.Server, 0, 1)
	handler := lb.NewProxy(k, g, r, conf)

	// a separate mgmt listener is requested? then let's create a LB traffic only server
	if conf.Listen != conf.MgmtListen {
		servers = append(servers, &http.Server{Addr: conf.Listen, Handler: handler})
		handler = lb.NullHandler()
	}

	// add mgmt endpoints to the handler
	handler = g.Wrap(handler) // add/del/list endpoints
	handler = r.Wrap(handler) // stats / dash endpoint

	servers = append(servers, &http.Server{Addr: conf.MgmtListen, Handler: handler})
	serve(servers, &conf)
}

func serve(servers []*http.Server, conf *lb.Config) {

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)

	for i := 0; i < len(servers); i++ {
		go func(idx int) {
			err := servers[idx].ListenAndServe()
			if err != nil && err != http.ErrServerClosed {
				logrus.WithFields(logrus.Fields{"server_id": idx}).WithError(err).Fatal("server error")
			} else {
				logrus.WithFields(logrus.Fields{"server_id": idx}).Info("server stopped")
			}
		}(i)
	}

	sig := <-ch
	logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")

	for i := 0; i < len(servers); i++ {

		ctx := context.Background()

		if conf.ShutdownTimeout > 0 {
			tmpCtx, cancel := context.WithTimeout(context.Background(), time.Duration(conf.ShutdownTimeout)*time.Second)
			ctx = tmpCtx
			defer cancel()
		}

		err := servers[i].Shutdown(ctx) // safe shutdown
		if err != nil {
			logrus.WithFields(logrus.Fields{"server_id": i}).WithError(err).Fatal("server shutdown error")
		} else {
			logrus.WithFields(logrus.Fields{"server_id": i}).Info("server shutdown")
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
	"github.com/sirupsen/logrus"
)

const VERSION = "0.0.235"

func main() {
	// XXX (reed): normalize
	level, err := logrus.ParseLevel(os.Getenv("LOG_LEVEL"))
	if err != nil {
		level = logrus.InfoLevel
	}
	logrus.SetLevel(level)

	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.202", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory; use k8s for kuberneted")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.StringVar(&conf.MgmtListen, "mgmt-listen", ":8081", "management port to run on")
	flag.IntVar(&conf.ShutdownTimeout, "shutdown-timeout", 0, "graceful shutdown timeout")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckHealthy, "hc-healthy", 1, "threshold of success checks to declare node healthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.StringVar(&conf.Namespace, "namespace", "", "kubernetes namespace to monitor")
	flag.StringVar(&conf.LabelSelector, "label-selector", "", "kubernetes label selector to monitor")
	flag.IntVar(&conf.TargetPort, "target-port", 8080, "kubernetes port to target on selected pods")

	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	db, err := lb.NewDB(conf) // Handles case where DBurl == "k8s"
	if err != nil {
		logrus.WithError(err).Fatal("error setting up database")
	}
	defer db.Close()

	g, err := lb.NewAllGrouper(conf, db)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	servers := make([]*http.Server, 0, 1)
	handler := lb.NewProxy(k, g, r, conf)

	// a separate mgmt listener is requested? then let's create a LB traffic only server
	if conf.Listen != conf.MgmtListen {
		servers = append(servers, &http.Server{Addr: conf.Listen, Handler: handler})
		handler = lb.NullHandler()
	}

	// add mgmt endpoints to the handler
	handler = g.Wrap(handler) // add/del/list endpoints
	handler = r.Wrap(handler) // stats / dash endpoint

	servers = append(servers, &http.Server{Addr: conf.MgmtListen, Handler: handler})
	serve(servers, &conf)
}

func serve(servers []*http.Server, conf *lb.Config) {

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)

	for i := 0; i < len(servers); i++ {
		go func(idx int) {
			err := servers[idx].ListenAndServe()
			if err != nil && err != http.ErrServerClosed {
				logrus.WithFields(logrus.Fields{"server_id": idx}).WithError(err).Fatal("server error")
			} else {
				logrus.WithFields(logrus.Fields{"server_id": idx}).Info("server stopped")
			}
		}(i)
	}

	sig := <-ch
	logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")

	for i := 0; i < len(servers); i++ {

		ctx := context.Background()

		if conf.ShutdownTimeout > 0 {
			tmpCtx, cancel := context.WithTimeout(context.Background(), time.Duration(conf.ShutdownTimeout)*time.Second)
			ctx = tmpCtx
			defer cancel()
		}

		err := servers[i].Shutdown(ctx) // safe shutdown
		if err != nil {
			logrus.WithFields(logrus.Fields{"server_id": i}).WithError(err).Fatal("server shutdown error")
		} else {
			logrus.WithFields(logrus.Fields{"server_id": i}).Info("server shutdown")
		}
	}
}
<commit_msg>fnlb: 0.0.236 release [skip ci]<commit_after>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
	"github.com/sirupsen/logrus"
)

const VERSION = "0.0.236"

func main() {
	// XXX (reed): normalize
	level, err := logrus.ParseLevel(os.Getenv("LOG_LEVEL"))
	if err != nil {
		level = logrus.InfoLevel
	}
	logrus.SetLevel(level)

	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.203", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory; use k8s for kuberneted")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.StringVar(&conf.MgmtListen, "mgmt-listen", ":8081", "management port to run on")
	flag.IntVar(&conf.ShutdownTimeout, "shutdown-timeout", 0, "graceful shutdown timeout")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckHealthy, "hc-healthy", 1, "threshold of success checks to declare node healthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.StringVar(&conf.Namespace, "namespace", "", "kubernetes namespace to monitor")
	flag.StringVar(&conf.LabelSelector, "label-selector", "", "kubernetes label selector to monitor")
	flag.IntVar(&conf.TargetPort, "target-port", 8080, "kubernetes port to target on selected pods")

	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	db, err := lb.NewDB(conf) // Handles case where DBurl == "k8s"
	if err != nil {
		logrus.WithError(err).Fatal("error setting up database")
	}
	defer db.Close()

	g, err := lb.NewAllGrouper(conf, db)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	servers := make([]*http.Server, 0, 1)
	handler := lb.NewProxy(k, g, r, conf)

	// a separate mgmt listener is requested? then let's create a LB traffic only server
	if conf.Listen != conf.MgmtListen {
		servers = append(servers, &http.Server{Addr: conf.Listen, Handler: handler})
		handler = lb.NullHandler()
	}

	// add mgmt endpoints to the handler
	handler = g.Wrap(handler) // add/del/list endpoints
	handler = r.Wrap(handler) // stats / dash endpoint

	servers = append(servers, &http.Server{Addr: conf.MgmtListen, Handler: handler})
	serve(servers, &conf)
}

func serve(servers []*http.Server, conf *lb.Config) {

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)

	for i := 0; i < len(servers); i++ {
		go func(idx int) {
			err := servers[idx].ListenAndServe()
			if err != nil && err != http.ErrServerClosed {
				logrus.WithFields(logrus.Fields{"server_id": idx}).WithError(err).Fatal("server error")
			} else {
				logrus.WithFields(logrus.Fields{"server_id": idx}).Info("server stopped")
			}
		}(i)
	}

	sig := <-ch
	logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")

	for i := 0; i < len(servers); i++ {

		ctx := context.Background()

		if conf.ShutdownTimeout > 0 {
			tmpCtx, cancel := context.WithTimeout(context.Background(), time.Duration(conf.ShutdownTimeout)*time.Second)
			ctx = tmpCtx
			defer cancel()
		}

		err := servers[i].Shutdown(ctx) // safe shutdown
		if err != nil {
			logrus.WithFields(logrus.Fields{"server_id": i}).WithError(err).Fatal("server shutdown error")
		} else {
			logrus.WithFields(logrus.Fields{"server_id": i}).Info("server shutdown")
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
	"github.com/sirupsen/logrus"
)

const VERSION = "0.0.204"

func main() {
	// XXX (reed): normalize
	level, err := logrus.ParseLevel(os.Getenv("LOG_LEVEL"))
	if err != nil {
		level = logrus.InfoLevel
	}
	logrus.SetLevel(level)

	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.171", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory; use k8s for kuberneted")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.StringVar(&conf.MgmtListen, "mgmt-listen", ":8081", "management port to run on")
	flag.IntVar(&conf.ShutdownTimeout, "shutdown-timeout", 0, "graceful shutdown timeout")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckHealthy, "hc-healthy", 1, "threshold of success checks to declare node healthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.StringVar(&conf.Namespace, "namespace", "", "kubernetes namespace to monitor")
	flag.StringVar(&conf.LabelSelector, "label-selector", "", "kubernetes label selector to monitor")
	flag.IntVar(&conf.TargetPort, "target-port", 8080, "kubernetes port to target on selected pods")

	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	db, err := lb.NewDB(conf) // Handles case where DBurl == "k8s"
	if err != nil {
		logrus.WithError(err).Fatal("error setting up database")
	}
	defer db.Close()

	g, err := lb.NewAllGrouper(conf, db)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	servers := make([]*http.Server, 0, 1)
	handler := lb.NewProxy(k, g, r, conf)

	// a separate mgmt listener is requested? then let's create a LB traffic only server
	if conf.Listen != conf.MgmtListen {
		servers = append(servers, &http.Server{Addr: conf.Listen, Handler: handler})
		handler = lb.NullHandler()
	}

	// add mgmt endpoints to the handler
	handler = g.Wrap(handler) // add/del/list endpoints
	handler = r.Wrap(handler) // stats / dash endpoint

	servers = append(servers, &http.Server{Addr: conf.MgmtListen, Handler: handler})
	serve(servers, &conf)
}

func serve(servers []*http.Server, conf *lb.Config) {

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)

	for i := 0; i < len(servers); i++ {
		go func(idx int) {
			err := servers[idx].ListenAndServe()
			if err != nil && err != http.ErrServerClosed {
				logrus.WithFields(logrus.Fields{"server_id": idx}).WithError(err).Fatal("server error")
			} else {
				logrus.WithFields(logrus.Fields{"server_id": idx}).Info("server stopped")
			}
		}(i)
	}

	sig := <-ch
	logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")

	for i := 0; i < len(servers); i++ {

		ctx := context.Background()

		if conf.ShutdownTimeout > 0 {
			tmpCtx, cancel := context.WithTimeout(context.Background(), time.Duration(conf.ShutdownTimeout)*time.Second)
			ctx = tmpCtx
			defer cancel()
		}

		err := servers[i].Shutdown(ctx) // safe shutdown
		if err != nil {
			logrus.WithFields(logrus.Fields{"server_id": i}).WithError(err).Fatal("server shutdown error")
		} else {
			logrus.WithFields(logrus.Fields{"server_id": i}).Info("server shutdown")
		}
	}
}
<commit_msg>fnlb: 0.0.205 release [skip ci]<commit_after>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
	"github.com/sirupsen/logrus"
)

const VERSION = "0.0.205"

func main() {
	// XXX (reed): normalize
	level, err := logrus.ParseLevel(os.Getenv("LOG_LEVEL"))
	if err != nil {
		level = logrus.InfoLevel
	}
	logrus.SetLevel(level)

	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.172", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory; use k8s for kuberneted")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.StringVar(&conf.MgmtListen, "mgmt-listen", ":8081", "management port to run on")
	flag.IntVar(&conf.ShutdownTimeout, "shutdown-timeout", 0, "graceful shutdown timeout")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckHealthy, "hc-healthy", 1, "threshold of success checks to declare node healthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.StringVar(&conf.Namespace, "namespace", "", "kubernetes namespace to monitor")
	flag.StringVar(&conf.LabelSelector, "label-selector", "", "kubernetes label selector to monitor")
	flag.IntVar(&conf.TargetPort, "target-port", 8080, "kubernetes port to target on selected pods")

	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	db, err := lb.NewDB(conf) // Handles case where DBurl == "k8s"
	if err != nil {
		logrus.WithError(err).Fatal("error setting up database")
	}
	defer db.Close()

	g, err := lb.NewAllGrouper(conf, db)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	servers := make([]*http.Server, 0, 1)
	handler := lb.NewProxy(k, g, r, conf)

	// a separate mgmt listener is requested? then let's create a LB traffic only server
	if conf.Listen != conf.MgmtListen {
		servers = append(servers, &http.Server{Addr: conf.Listen, Handler: handler})
		handler = lb.NullHandler()
	}

	// add mgmt endpoints to the handler
	handler = g.Wrap(handler) // add/del/list endpoints
	handler = r.Wrap(handler) // stats / dash endpoint

	servers = append(servers, &http.Server{Addr: conf.MgmtListen, Handler: handler})
	serve(servers, &conf)
}

func serve(servers []*http.Server, conf *lb.Config) {

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)

	for i := 0; i < len(servers); i++ {
		go func(idx int) {
			err := servers[idx].ListenAndServe()
			if err != nil && err != http.ErrServerClosed {
				logrus.WithFields(logrus.Fields{"server_id": idx}).WithError(err).Fatal("server error")
			} else {
				logrus.WithFields(logrus.Fields{"server_id": idx}).Info("server stopped")
			}
		}(i)
	}

	sig := <-ch
	logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")

	for i := 0; i < len(servers); i++ {

		ctx := context.Background()

		if conf.ShutdownTimeout > 0 {
			tmpCtx, cancel := context.WithTimeout(context.Background(), time.Duration(conf.ShutdownTimeout)*time.Second)
			ctx = tmpCtx
			defer cancel()
		}

		err := servers[i].Shutdown(ctx) // safe shutdown
		if err != nil {
			logrus.WithFields(logrus.Fields{"server_id": i}).WithError(err).Fatal("server shutdown error")
		} else {
			logrus.WithFields(logrus.Fields{"server_id": i}).Info("server shutdown")
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
	"github.com/sirupsen/logrus"
)

const VERSION = "0.0.79"

func main() {
	// XXX (reed): normalize
	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.46", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	g, err := lb.NewAllGrouper(conf)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	h := lb.NewProxy(k, g, r, conf)
	h = g.Wrap(h) // add/del/list endpoints
	h = r.Wrap(h) // stats / dash endpoint

	err = serve(conf.Listen, h)
	if err != nil {
		logrus.WithError(err).Fatal("server error")
	}
}

func serve(addr string, handler http.Handler) error {
	server := &http.Server{Addr: addr, Handler: handler}

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)
	go func() {
		for sig := range ch {
			logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")
			server.Shutdown(context.Background()) // safe shutdown
			return
		}
	}()
	return server.ListenAndServe()
}
<commit_msg>fnlb: 0.0.80 release [skip ci]<commit_after>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
	"github.com/sirupsen/logrus"
)

const VERSION = "0.0.80"

func main() {
	// XXX (reed): normalize
	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.47", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	g, err := lb.NewAllGrouper(conf)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	h := lb.NewProxy(k, g, r, conf)
	h = g.Wrap(h) // add/del/list endpoints
	h = r.Wrap(h) // stats / dash endpoint

	err = serve(conf.Listen, h)
	if err != nil {
		logrus.WithError(err).Fatal("server error")
	}
}

func serve(addr string, handler http.Handler) error {
	server := &http.Server{Addr: addr, Handler: handler}

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)
	go func() {
		for sig := range ch {
			logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")
			server.Shutdown(context.Background()) // safe shutdown
			return
		}
	}()
	return server.ListenAndServe()
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"os"
	"fmt"
	"golang.org/x/text/width"
)

func main() {
	var bio = bufio.NewReader(os.Stdin)

	var line, _, err = bio.ReadLine()
	if err != nil {
		print(err.Error())
		os.Exit(1)
	}

	var widener = width.Widen
	var wideline = widener.String(string(line))
	fmt.Println(wideline)
}
<commit_msg>Added multiline support<commit_after>package main

import (
	"bufio"
	"os"
	"fmt"
	"golang.org/x/text/width"
)

func main() {
	var bio = bufio.NewReader(os.Stdin)

	for {
		var line, _, err= bio.ReadLine()
		if err != nil {
			os.Exit(0)
		}
		var wideline = width.Widen.String(string(line))
		fmt.Println(wideline)
	}
}
<|endoftext|>


<commit_before>package gosom

import "math"

// A DistanceFunction calculates and returns the distance between to points.
type DistanceFunction func(from, to []float64) (distance float64)

// A CoolingFunction returns the cooling alpha [1..0] for an input value [0..1].
type CoolingFunction func(input float64) (output float64)

// A NeighborhoodFunction returns the influence [1..0] of a distance [0..1].
type NeighborhoodFunction func(distance float64) (influence float64)

func EuclideanDistance(from, to []float64) (distance float64) {
	d := 0.0
	l := Min(len(from), len(to))

	for i:=0; i<l; i++ {
		d += (from[i] - to[i]) * (from[i] - to[i])
	}

	return math.Sqrt(d)
}

func ManhattanDistance(from, to []float64) (distance float64) {
	d := 0.0
	l := Min(len(from), len(to))

	for i:=0; i<l; i++ {
		d += math.Abs(to[i]- from[i])
	}

	return d
}

func LinearCooling(input float64) (output float64) {
	return 1.0 - input
}

func SoftCooling(input float64) (output float64) {
	d := -math.Log(0.2 / 1.2)
	return (1.2 * math.Exp(-input * d)) - 0.2
}

func MediumCooling(input float64) (output float64) {
	return 1.005 * math.Pow(0.005 / 1.0, input) - 0.005
}

func HardCooling(input float64) (output float64) {
	d := 1.0 / 101.0
	return (1.0 + d) / (1 + 100 * input) - d
}

func BubbleNeighborhood(distance float64) (influence float64) {
	d := math.Abs(distance)

	if d < 1.0 {
		return 1.0
	} else {
		return 0.0
	}
}

func ConeNeighborhood(distance float64) (influence float64) {
	d := math.Abs(distance)

	if d < 1.0 {
		return (1.0 - d) / 1.0
	} else {
		return 0.0
	}
}

func GaussianNeighborhood(distance float64) (influence float64) {
	stdDev := 5.5
	norm := (2.0 * math.Pow(2.0, 2.0)) / math.Pow(stdDev, 2.0)
	return math.Exp((-distance * distance) / norm)
}

func MexicanHatNeighborhood(distance float64) (influence float64) {
	norm := 3.0 / 2.0
	square := math.Pow(distance * norm, 2.0)
	return (1.0 - square) * math.Exp(-square)
}
<commit_msg>updated doc<commit_after>package gosom

import "math"

// A DistanceFunction calculates the distance between to points.
type DistanceFunction func(from, to []float64) (distance float64)

// A CoolingFunction calculates the cooling alpha [1..0] for an input value [0..1].
type CoolingFunction func(input float64) (output float64)

// A NeighborhoodFunction calculates the influence [1..0] of a distance [0..1..2].
type NeighborhoodFunction func(distance float64) (influence float64)

func EuclideanDistance(from, to []float64) (distance float64) {
	d := 0.0
	l := Min(len(from), len(to))

	for i:=0; i<l; i++ {
		d += (from[i] - to[i]) * (from[i] - to[i])
	}

	return math.Sqrt(d)
}

func ManhattanDistance(from, to []float64) (distance float64) {
	d := 0.0
	l := Min(len(from), len(to))

	for i:=0; i<l; i++ {
		d += math.Abs(to[i]- from[i])
	}

	return d
}

func LinearCooling(input float64) (output float64) {
	return 1.0 - input
}

func SoftCooling(input float64) (output float64) {
	d := -math.Log(0.2 / 1.2)
	return (1.2 * math.Exp(-input * d)) - 0.2
}

func MediumCooling(input float64) (output float64) {
	return 1.005 * math.Pow(0.005 / 1.0, input) - 0.005
}

func HardCooling(input float64) (output float64) {
	d := 1.0 / 101.0
	return (1.0 + d) / (1 + 100 * input) - d
}

func BubbleNeighborhood(distance float64) (influence float64) {
	d := math.Abs(distance)

	if d < 1.0 {
		return 1.0
	} else {
		return 0.0
	}
}

func ConeNeighborhood(distance float64) (influence float64) {
	d := math.Abs(distance)

	if d < 1.0 {
		return (1.0 - d) / 1.0
	} else {
		return 0.0
	}
}

func GaussianNeighborhood(distance float64) (influence float64) {
	stdDev := 5.5
	norm := (2.0 * math.Pow(2.0, 2.0)) / math.Pow(stdDev, 2.0)
	return math.Exp((-distance * distance) / norm)
}

func MexicanHatNeighborhood(distance float64) (influence float64) {
	norm := 3.0 / 2.0
	square := math.Pow(distance * norm, 2.0)
	return (1.0 - square) * math.Exp(-square)
}
<|endoftext|>