<commit_before>package hdsfhir

import (
	"encoding/json"
	"fmt"
	"github.com/intervention-engine/fhir/models"
	"net/http"
)

type Medication struct {
	Entry
	Route   map[string]string
	BaseUrl string
}

type FHIRMedicationWrapper struct {
	Medication models.Medication
	ServerURL  string
}

func (f FHIRMedicationWrapper) ToJSON() []byte {
	json, _ := json.Marshal(f.Medication)
	return json
}

func (f FHIRMedicationWrapper) SetServerURL(url string) {
	f.ServerURL = url
}

func NewMedicationWrapper(med Medication) FHIRMedicationWrapper {
	fhirMedication := models.Medication{}
	fhirMedication.Code = med.ConvertCodingToFHIR()
	fhirMedication.Name = med.Description
	return FHIRMedicationWrapper{Medication: fhirMedication}
}

func (m *Medication) ToFhirModel() models.MedicationStatement {
	fhirMedication := models.MedicationStatement{}
	fhirMedication.WhenGiven = m.AsFHIRPeriod()
	fhirMedication.Patient = models.Reference{Reference: m.Patient.ServerURL}
	medUrl := m.FindOrCreateFHIRMed()
	fhirMedication.Medication = models.Reference{Reference: medUrl}
	return fhirMedication
}

func (m *Medication) ToJSON() []byte {
	json, _ := json.Marshal(m.ToFhirModel())
	return json
}

func (m *Medication) FindOrCreateFHIRMed() string {
	var medicationQueryUrl string
	_, rxNormPresent := m.Codes["RxNorm"]
	if rxNormPresent {
		firstRxNormCode := m.Codes["RxNorm"][0]
		medicationQueryUrl = fmt.Sprintf("%s/Medication?code=%s|%s", m.BaseUrl, "http://www.nlm.nih.gov/research/umls/rxnorm/", firstRxNormCode)
	}

	_, ndcPresent := m.Codes["NDC"]
	if ndcPresent {
		firstNDCCode := m.Codes["NDC"]
		medicationQueryUrl = fmt.Sprintf("%s/Medication?code=%s|%s", m.BaseUrl, "http://www.fda.gov/Drugs/InformationOnDrugs", firstNDCCode)
	}

	resp, err := http.Get(medicationQueryUrl)
	defer resp.Body.Close()
	if err != nil {
		panic(err)
	}
	decoder := json.NewDecoder(resp.Body)
	medicationBundle := &models.MedicationBundle{}
	err = decoder.Decode(medicationBundle)
	if err != nil {
		panic(err)
	}
	if medicationBundle.TotalResults > 0 {
		return fmt.Sprintf("%s/Medication/%s", m.BaseUrl, medicationBundle.Entry[0].Id)
	} else {
		fhirWrapper := NewMedicationWrapper(*m)
		Upload(fhirWrapper, fmt.Sprintf("%s/Medication", m.BaseUrl))
		return fhirWrapper.ServerURL
	}
}
<commit_msg>Returning a pointer to a med wrapper instead of just the value<commit_after>package hdsfhir

import (
	"encoding/json"
	"fmt"
	"github.com/intervention-engine/fhir/models"
	"net/http"
)

type Medication struct {
	Entry
	Route   map[string]string
	BaseUrl string
}

type FHIRMedicationWrapper struct {
	Medication models.Medication
	ServerURL  string
}

func (f FHIRMedicationWrapper) ToJSON() []byte {
	json, _ := json.Marshal(f.Medication)
	return json
}

func (f FHIRMedicationWrapper) SetServerURL(url string) {
	f.ServerURL = url
}

func NewMedicationWrapper(med Medication) *FHIRMedicationWrapper {
	fhirMedication := models.Medication{}
	fhirMedication.Code = med.ConvertCodingToFHIR()
	fhirMedication.Name = med.Description
	return &FHIRMedicationWrapper{Medication: fhirMedication}
}

func (m *Medication) ToFhirModel() models.MedicationStatement {
	fhirMedication := models.MedicationStatement{}
	fhirMedication.WhenGiven = m.AsFHIRPeriod()
	fhirMedication.Patient = models.Reference{Reference: m.Patient.ServerURL}
	medUrl := m.FindOrCreateFHIRMed()
	fhirMedication.Medication = models.Reference{Reference: medUrl}
	return fhirMedication
}

func (m *Medication) ToJSON() []byte {
	json, _ := json.Marshal(m.ToFhirModel())
	return json
}

func (m *Medication) FindOrCreateFHIRMed() string {
	var medicationQueryUrl string
	_, rxNormPresent := m.Codes["RxNorm"]
	if rxNormPresent {
		firstRxNormCode := m.Codes["RxNorm"][0]
		medicationQueryUrl = fmt.Sprintf("%s/Medication?code=%s|%s", m.BaseUrl, "http://www.nlm.nih.gov/research/umls/rxnorm/", firstRxNormCode)
	}

	_, ndcPresent := m.Codes["NDC"]
	if ndcPresent {
		firstNDCCode := m.Codes["NDC"]
		medicationQueryUrl = fmt.Sprintf("%s/Medication?code=%s|%s", m.BaseUrl, "http://www.fda.gov/Drugs/InformationOnDrugs", firstNDCCode)
	}

	resp, err := http.Get(medicationQueryUrl)
	defer resp.Body.Close()
	if err != nil {
		panic(err)
	}
	decoder := json.NewDecoder(resp.Body)
	medicationBundle := &models.MedicationBundle{}
	err = decoder.Decode(medicationBundle)
	if err != nil {
		panic(err)
	}
	if medicationBundle.TotalResults > 0 {
		return fmt.Sprintf("%s/Medication/%s", m.BaseUrl, medicationBundle.Entry[0].Id)
	} else {
		fhirWrapper := NewMedicationWrapper(*m)
		Upload(fhirWrapper, fmt.Sprintf("%s/Medication", m.BaseUrl))
		return fhirWrapper.ServerURL
	}
}
<|endoftext|>


<commit_before>package csvutil

import (
	"strconv"

	"github.com/pkg/errors"
)

type column struct {
	symbol string
	index  int
	found  bool
}

func (c *column) findIndex(hdr []string) error {
	if isDigit(c.symbol) {
		i, _ := strconv.Atoi(c.symbol)
		c.index = i
		c.found = true
		return nil
	}
	if hdr == nil {
		return errors.New("not number column symbol")
	}
	for i, h := range hdr {
		if h == c.symbol {
			c.index = i
			c.found = true
			return nil
		}
	}
	return errors.Errorf("column %s not found", c.symbol)
}

func newColumn(sym string) *column {
	return &column{
		symbol: sym,
		index:  -1,
	}
}

func newColumns(syms []string) []*column {
	cols := make([]*column, len(syms))
	for i, sym := range syms {
		cols[i] = newColumn(sym)
	}
	return cols
}

func newColumnWithIndex(sym string, hdr []string) (*column, error) {
	col := newColumn(sym)
	err := col.findIndex(hdr)
	if err != nil {
		return nil, err
	}
	return col, nil
}

func newColumnsWithIndexes(syms []string, hdr []string) ([]*column, error) {
	cols := newColumns(syms)
	for _, col := range cols {
		err := col.findIndex(hdr)
		if err != nil {
			return nil, err
		}
	}
	return cols, nil
}

func newUniqueColumns(syms []string, hdr []string) ([]*column, error) {
	cols, err := newColumnsWithIndexes(syms, hdr)
	if err != nil {
		return nil, err
	}
	return uniqColumns(cols), nil
}

func uniqColumns(cols []*column) []*column {
	var newCols []*column
	for _, col := range cols {
		exists := false
		for _, newCol := range newCols {
			if newCol.index == col.index {
				exists = true
				break
			}
		}
		if col.index != -1 && !exists {
			newCols = append(newCols, col)
		}
	}
	return newCols
}
<commit_msg>どこからも使用されていない column.found を削除<commit_after>package csvutil

import (
	"strconv"

	"github.com/pkg/errors"
)

type column struct {
	symbol string
	index  int
}

func (c *column) findIndex(hdr []string) error {
	if isDigit(c.symbol) {
		i, _ := strconv.Atoi(c.symbol)
		c.index = i
		return nil
	}
	if hdr == nil {
		return errors.New("not number column symbol")
	}
	for i, h := range hdr {
		if h == c.symbol {
			c.index = i
			return nil
		}
	}
	return errors.Errorf("column %s not found", c.symbol)
}

func newColumn(sym string) *column {
	return &column{
		symbol: sym,
		index:  -1,
	}
}

func newColumns(syms []string) []*column {
	cols := make([]*column, len(syms))
	for i, sym := range syms {
		cols[i] = newColumn(sym)
	}
	return cols
}

func newColumnWithIndex(sym string, hdr []string) (*column, error) {
	col := newColumn(sym)
	err := col.findIndex(hdr)
	if err != nil {
		return nil, err
	}
	return col, nil
}

func newColumnsWithIndexes(syms []string, hdr []string) ([]*column, error) {
	cols := newColumns(syms)
	for _, col := range cols {
		err := col.findIndex(hdr)
		if err != nil {
			return nil, err
		}
	}
	return cols, nil
}

func newUniqueColumns(syms []string, hdr []string) ([]*column, error) {
	cols, err := newColumnsWithIndexes(syms, hdr)
	if err != nil {
		return nil, err
	}
	return uniqColumns(cols), nil
}

func uniqColumns(cols []*column) []*column {
	var newCols []*column
	for _, col := range cols {
		exists := false
		for _, newCol := range newCols {
			if newCol.index == col.index {
				exists = true
				break
			}
		}
		if col.index != -1 && !exists {
			newCols = append(newCols, col)
		}
	}
	return newCols
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Contributor: Aaron Meihm ameihm@mozilla.com [:alm]

// runner-scribe is a mig-runner plugin that processes results coming from automated
// actions and forwards the results as vulnerability events to MozDef
package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"strings"

	"github.com/jvehent/gozdef"
	"gopkg.in/gcfg.v1"
	"mig.ninja/mig"
	scribemod "mig.ninja/mig/modules/scribe"
)

// config represents the configuration used by runner-scribe, and is read in on
// initialization
//
// URL and Source are mandatory settings
type config struct {
	MozDef struct {
		URL    string // URL to post events to MozDef
		Source string // Source identifier for vulnerability events
	}
}

const configPath string = "/etc/mig/runner-scribe.conf"

var conf config

func main() {
	defer func() {
		if e := recover(); e != nil {
			fmt.Fprintf(os.Stderr, "error: %v\n", e)
			os.Exit(1)
		}
	}()

	var (
		err     error
		results mig.RunnerResult
	)

	err = gcfg.ReadFileInto(&conf, configPath)
	if err != nil {
		panic(err)
	}

	buf, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		panic(err)
	}
	err = json.Unmarshal(buf, &results)
	if err != nil {
		panic(err)
	}
	var items []gozdef.VulnEvent
	for _, x := range results.Commands {
		// Process the incoming commands, under normal circumstances we will have one
		// returned command per host. However, this function can handle cases where
		// more than one command applies to a given host. If data for a host already
		// exists in items, makeVulnerability should attempt to append this data to
		// the host rather than add a new item.
		var err error
		items, err = makeVulnerability(items, x)
		if err != nil {
			panic(err)
		}
	}
	for _, y := range items {
		err = sendVulnerability(y)
		if err != nil {
			panic(err)
		}
	}
}

func sendVulnerability(item gozdef.VulnEvent) (err error) {
	ac := gozdef.APIConf{URL: conf.MozDef.URL}
	pub, err := gozdef.InitAPI(ac)
	if err != nil {
		return
	}
	err = pub.Send(item)
	return
}

func makeVulnerability(initems []gozdef.VulnEvent, cmd mig.Command) (items []gozdef.VulnEvent, err error) {
	var (
		itemptr                       *gozdef.VulnEvent
		assethostname, assetipaddress string
		insertNew                     bool
	)
	items = initems

	assethostname = cmd.Agent.Name
	for _, x := range cmd.Agent.Env.Addresses {
		if !strings.Contains(x, ".") {
			continue
		}
		ipt, _, err := net.ParseCIDR(x)
		if err != nil {
			continue
		}
		assetipaddress = ipt.String()
		break
	}

	// First, see if we can locate a preexisting item for this asset
	for i := range items {
		if items[i].Asset.Hostname == assethostname &&
			items[i].Asset.IPAddress == assetipaddress {
			itemptr = &items[i]
			break
		}
	}
	if itemptr == nil {
		// Initialize a new event we will insert later
		newevent, err := gozdef.NewVulnEvent()
		if err != nil {
			return items, err
		}
		newevent.Description = "MIG vulnerability identification"
		newevent.Zone = "mig"
		newevent.Asset.Hostname = assethostname
		newevent.Asset.IPAddress = assetipaddress
		newevent.Asset.OS = cmd.Agent.Env.OS
		if len(cmd.Agent.Tags) != 0 {
			if _, ok := cmd.Agent.Tags["operator"]; ok {
				newevent.Asset.Owner.Operator = cmd.Agent.Tags["operator"]
			}
		}
		// Always set credentialed checks here
		newevent.CredentialedChecks = true
		insertNew = true
		itemptr = &newevent
	}

	for _, result := range cmd.Results {
		var el scribemod.ScribeElements
		err = result.GetElements(&el)
		if err != nil {
			return items, err
		}
		for _, x := range el.Results {
			itemptr.SourceName = conf.MozDef.Source
			if !x.MasterResult {
				// Result was false (vulnerability did not match)
				continue
			}
			newve := gozdef.VulnVuln{}
			newve.Name = x.TestName
			for _, y := range x.Tags {
				if y.Key == "severity" {
					newve.Risk = y.Value
				} else if y.Key == "link" {
					newve.Link = y.Value
				}
			}
			// If no risk value is set on the vulnerability, we just treat this as
			// informational and ignore it. This will apply to things like the result
			// from platform dependency checks associated with real vulnerability checks.
			if newve.Risk == "" {
				continue
			}
			newve.Risk = normalizeRisk(newve.Risk)
			newve.LikelihoodIndicator = likelihoodFromRisk(newve.Risk)
			if newve.CVSS == "" {
				newve.CVSS = cvssFromRisk(newve.Risk)
			}
			// Use the identifier for each true subresult in the
			// test as a proof section
			for _, y := range x.Results {
				if y.Result {
					newve.Packages = append(newve.Packages, y.Identifier)
				}
			}
			itemptr.Vuln = append(itemptr.Vuln, newve)
		}
	}
	if insertNew {
		items = append(items, *itemptr)
	}
	return
}

// cvssFromRisk returns a synthesized CVSS score as a string given a risk label
func cvssFromRisk(risk string) string {
	switch risk {
	case "critical":
		return "10.0"
	case "high":
		return "8.0"
	case "medium":
		return "5.0"
	case "low":
		return "2.5"
	}
	return "0.0"
}

// likelihoodFromRisk returns a likelihood indicator value given a risk label
func likelihoodFromRisk(risk string) string {
	switch risk {
	case "high":
		return "high"
	case "medium":
		return "medium"
	case "low":
		return "low"
	case "critical":
		return "maximum"
	}
	return "unknown"
}

// normalizeRisk converts known risk labels into a standardized form, if we can't identify
// the value we just return it as is
func normalizeRisk(in string) string {
	switch strings.ToLower(in) {
	case "high":
		return "high"
	case "medium":
		return "medium"
	case "low":
		return "low"
	case "critical":
		return "critical"
	}
	return in
}
<commit_msg>runner-scribe: apply a v2bkey based on operator and team values<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Contributor: Aaron Meihm ameihm@mozilla.com [:alm]

// runner-scribe is a mig-runner plugin that processes results coming from automated
// actions and forwards the results as vulnerability events to MozDef
package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"strings"

	"github.com/jvehent/gozdef"
	"gopkg.in/gcfg.v1"
	"mig.ninja/mig"
	scribemod "mig.ninja/mig/modules/scribe"
)

// config represents the configuration used by runner-scribe, and is read in on
// initialization
//
// URL and Source are mandatory settings
type config struct {
	MozDef struct {
		URL    string // URL to post events to MozDef
		Source string // Source identifier for vulnerability events
	}
}

const configPath string = "/etc/mig/runner-scribe.conf"

var conf config

func main() {
	defer func() {
		if e := recover(); e != nil {
			fmt.Fprintf(os.Stderr, "error: %v\n", e)
			os.Exit(1)
		}
	}()

	var (
		err     error
		results mig.RunnerResult
	)

	err = gcfg.ReadFileInto(&conf, configPath)
	if err != nil {
		panic(err)
	}

	buf, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		panic(err)
	}
	err = json.Unmarshal(buf, &results)
	if err != nil {
		panic(err)
	}
	var items []gozdef.VulnEvent
	for _, x := range results.Commands {
		// Process the incoming commands, under normal circumstances we will have one
		// returned command per host. However, this function can handle cases where
		// more than one command applies to a given host. If data for a host already
		// exists in items, makeVulnerability should attempt to append this data to
		// the host rather than add a new item.
		var err error
		items, err = makeVulnerability(items, x)
		if err != nil {
			panic(err)
		}
	}
	for _, y := range items {
		err = sendVulnerability(y)
		if err != nil {
			panic(err)
		}
	}
}

func sendVulnerability(item gozdef.VulnEvent) (err error) {
	ac := gozdef.APIConf{URL: conf.MozDef.URL}
	pub, err := gozdef.InitAPI(ac)
	if err != nil {
		return
	}
	err = pub.Send(item)
	return
}

func makeVulnerability(initems []gozdef.VulnEvent, cmd mig.Command) (items []gozdef.VulnEvent, err error) {
	var (
		itemptr                       *gozdef.VulnEvent
		assethostname, assetipaddress string
		insertNew                     bool
	)
	items = initems

	assethostname = cmd.Agent.Name
	for _, x := range cmd.Agent.Env.Addresses {
		if !strings.Contains(x, ".") {
			continue
		}
		ipt, _, err := net.ParseCIDR(x)
		if err != nil {
			continue
		}
		assetipaddress = ipt.String()
		break
	}

	// First, see if we can locate a preexisting item for this asset
	for i := range items {
		if items[i].Asset.Hostname == assethostname &&
			items[i].Asset.IPAddress == assetipaddress {
			itemptr = &items[i]
			break
		}
	}
	if itemptr == nil {
		// Initialize a new event we will insert later
		newevent, err := gozdef.NewVulnEvent()
		if err != nil {
			return items, err
		}
		newevent.Description = "MIG vulnerability identification"
		newevent.Zone = "mig"
		newevent.Asset.Hostname = assethostname
		newevent.Asset.IPAddress = assetipaddress
		newevent.Asset.OS = cmd.Agent.Env.OS
		if len(cmd.Agent.Tags) != 0 {
			if _, ok := cmd.Agent.Tags["operator"]; ok {
				newevent.Asset.Owner.Operator = cmd.Agent.Tags["operator"]
			}
		}
		// Apply a v2bkey to the event. This should be set using integration
		// with service-map, but here for now we just apply it based on the operator
		// and team values which may be present in the event.
		if newevent.Asset.Owner.V2Bkey == "" {
			if newevent.Asset.Owner.Operator != "" {
				newevent.Asset.Owner.V2Bkey = newevent.Asset.Owner.Operator
			}
			if newevent.Asset.Owner.Team != "" {
				newevent.Asset.Owner.V2Bkey += "-" + newevent.Asset.Owner.Team
			}
		}
		// Always set credentialed checks here
		newevent.CredentialedChecks = true
		insertNew = true
		itemptr = &newevent
	}

	for _, result := range cmd.Results {
		var el scribemod.ScribeElements
		err = result.GetElements(&el)
		if err != nil {
			return items, err
		}
		for _, x := range el.Results {
			itemptr.SourceName = conf.MozDef.Source
			if !x.MasterResult {
				// Result was false (vulnerability did not match)
				continue
			}
			newve := gozdef.VulnVuln{}
			newve.Name = x.TestName
			for _, y := range x.Tags {
				if y.Key == "severity" {
					newve.Risk = y.Value
				} else if y.Key == "link" {
					newve.Link = y.Value
				}
			}
			// If no risk value is set on the vulnerability, we just treat this as
			// informational and ignore it. This will apply to things like the result
			// from platform dependency checks associated with real vulnerability checks.
			if newve.Risk == "" {
				continue
			}
			newve.Risk = normalizeRisk(newve.Risk)
			newve.LikelihoodIndicator = likelihoodFromRisk(newve.Risk)
			if newve.CVSS == "" {
				newve.CVSS = cvssFromRisk(newve.Risk)
			}
			// Use the identifier for each true subresult in the
			// test as a proof section
			for _, y := range x.Results {
				if y.Result {
					newve.Packages = append(newve.Packages, y.Identifier)
				}
			}
			itemptr.Vuln = append(itemptr.Vuln, newve)
		}
	}
	if insertNew {
		items = append(items, *itemptr)
	}
	return
}

// cvssFromRisk returns a synthesized CVSS score as a string given a risk label
func cvssFromRisk(risk string) string {
	switch risk {
	case "critical":
		return "10.0"
	case "high":
		return "8.0"
	case "medium":
		return "5.0"
	case "low":
		return "2.5"
	}
	return "0.0"
}

// likelihoodFromRisk returns a likelihood indicator value given a risk label
func likelihoodFromRisk(risk string) string {
	switch risk {
	case "high":
		return "high"
	case "medium":
		return "medium"
	case "low":
		return "low"
	case "critical":
		return "maximum"
	}
	return "unknown"
}

// normalizeRisk converts known risk labels into a standardized form, if we can't identify
// the value we just return it as is
func normalizeRisk(in string) string {
	switch strings.ToLower(in) {
	case "high":
		return "high"
	case "medium":
		return "medium"
	case "low":
		return "low"
	case "critical":
		return "critical"
	}
	return in
}
<|endoftext|>


<commit_before>package datadog

import (
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
	"time"

	"github.com/DataDog/datadog-go/statsd"
	"github.com/sirupsen/logrus"
	"github.com/stretchr/testify/assert"
	"github.com/stripe/veneur/samplers"
	"github.com/stripe/veneur/ssf"
)

// DDMetricsRequest represents the body of the POST request
// for sending metrics data to Datadog
// Eventually we'll want to define this symmetrically.
type DDMetricsRequest struct {
	Series []DDMetric
}

type DatadogRoundTripper struct {
	Endpoint      string
	Contains      string
	GotCalled     bool
	ThingReceived bool
}

func (rt *DatadogRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
	rec := httptest.NewRecorder()
	if strings.HasPrefix(req.URL.Path, rt.Endpoint) {
		body, _ := ioutil.ReadAll(req.Body)
		defer req.Body.Close()
		if strings.Contains(string(body), rt.Contains) {
			rt.ThingReceived = true
		}

		rec.Code = http.StatusOK
		rt.GotCalled = true
	}

	return rec.Result(), nil
}

func TestDatadogRate(t *testing.T) {
	ddSink := DatadogMetricSink{
		hostname: "somehostname",
		tags:     []string{"a:b", "c:d"},
		interval: 10,
	}

	metrics := []samplers.InterMetric{{
		Name:      "foo.bar.baz",
		Timestamp: time.Now().Unix(),
		Value:     float64(10),
		Tags:      []string{"gorch:frobble", "x:e"},
		Type:      samplers.CounterMetric,
	}}
	ddMetrics := ddSink.finalizeMetrics(metrics)
	assert.Equal(t, "rate", ddMetrics[0].MetricType, "Metric type should be rate")
	assert.Equal(t, float64(1.0), ddMetrics[0].Value[0][1], "Metric rate wasnt computed correctly")
}

func TestServerTags(t *testing.T) {
	ddSink := DatadogMetricSink{
		hostname: "somehostname",
		tags:     []string{"a:b", "c:d"},
		interval: 10,
	}

	metrics := []samplers.InterMetric{{
		Name:      "foo.bar.baz",
		Timestamp: time.Now().Unix(),
		Value:     float64(10),
		Tags:      []string{"gorch:frobble", "x:e"},
		Type:      samplers.CounterMetric,
	}}

	ddMetrics := ddSink.finalizeMetrics(metrics)
	assert.Equal(t, "somehostname", ddMetrics[0].Hostname, "Metric hostname uses argument")
	assert.Contains(t, ddMetrics[0].Tags, "a:b", "Tags should contain server tags")
}

func TestHostMagicTag(t *testing.T) {
	ddSink := DatadogMetricSink{
		hostname: "badhostname",
		tags:     []string{"a:b", "c:d"},
	}

	metrics := []samplers.InterMetric{{
		Name:      "foo.bar.baz",
		Timestamp: time.Now().Unix(),
		Value:     float64(10),
		Tags:      []string{"gorch:frobble", "host:abc123", "x:e"},
		Type:      samplers.CounterMetric,
	}}

	ddMetrics := ddSink.finalizeMetrics(metrics)
	assert.Equal(t, "abc123", ddMetrics[0].Hostname, "Metric hostname should be from tag")
	assert.NotContains(t, ddMetrics[0].Tags, "host:abc123", "Host tag should be removed")
	assert.Contains(t, ddMetrics[0].Tags, "x:e", "Last tag is still around")
}

func TestDeviceMagicTag(t *testing.T) {
	ddSink := DatadogMetricSink{
		hostname: "badhostname",
		tags:     []string{"a:b", "c:d"},
	}

	metrics := []samplers.InterMetric{{
		Name:      "foo.bar.baz",
		Timestamp: time.Now().Unix(),
		Value:     float64(10),
		Tags:      []string{"gorch:frobble", "device:abc123", "x:e"},
		Type:      samplers.CounterMetric,
	}}

	ddMetrics := ddSink.finalizeMetrics(metrics)
	assert.Equal(t, "abc123", ddMetrics[0].DeviceName, "Metric devicename should be from tag")
	assert.NotContains(t, ddMetrics[0].Tags, "device:abc123", "Host tag should be removed")
	assert.Contains(t, ddMetrics[0].Tags, "x:e", "Last tag is still around")
}

func TestNewDatadogSpanSinkConfig(t *testing.T) {
	// test the variables that have been renamed
	stats, _ := statsd.NewBuffered("localhost:1235", 1024)
	ddSink, err := NewDatadogSpanSink("http://example.com", 100, stats, &http.Client{}, nil, logrus.New())
	if err != nil {
		t.Fatal(err)
	}
	err = ddSink.Start(nil)
	if err != nil {
		t.Fatal(err)
	}

	assert.Equal(t, "http://example.com", ddSink.traceAddress)
}

func TestDatadogFlushSpans(t *testing.T) {
	// test the variables that have been renamed
	stats, _ := statsd.NewBuffered("localhost:1235", 1024)

	transport := &DatadogRoundTripper{Endpoint: "/spans", Contains: "farts-srv"}

	ddSink, err := NewDatadogSpanSink("http://example.com", 100, stats, &http.Client{Transport: transport}, nil, logrus.New())
	assert.NoError(t, err)

	start := time.Now()
	end := start.Add(2 * time.Second)

	testSpan := &ssf.SSFSpan{
		TraceId:        1,
		ParentId:       1,
		Id:             2,
		StartTimestamp: int64(start.UnixNano()),
		EndTimestamp:   int64(end.UnixNano()),
		Error:          false,
		Service:        "farts-srv",
		Tags: map[string]string{
			"baz": "qux",
		},
		Indicator: false,
		Name:      "farting farty farts",
	}
	err = ddSink.Ingest(testSpan)
	assert.NoError(t, err)

	ddSink.Flush()
	assert.Equal(t, true, transport.GotCalled, "Did not call spans endpoint")
}
<commit_msg>Move all sinks to their own packages, refactor tests accordingly.<commit_after>package datadog

import (
	"net/http"
	"testing"
	"time"

	"github.com/DataDog/datadog-go/statsd"
	"github.com/sirupsen/logrus"
	"github.com/stretchr/testify/assert"
	"github.com/stripe/veneur/samplers"
)

// DDMetricsRequest represents the body of the POST request
// for sending metrics data to Datadog
// Eventually we'll want to define this symmetrically.
type DDMetricsRequest struct {
	Series []DDMetric
}

func TestDatadogRate(t *testing.T) {
	ddSink := DatadogMetricSink{
		hostname: "somehostname",
		tags:     []string{"a:b", "c:d"},
		interval: 10,
	}

	metrics := []samplers.InterMetric{{
		Name:      "foo.bar.baz",
		Timestamp: time.Now().Unix(),
		Value:     float64(10),
		Tags:      []string{"gorch:frobble", "x:e"},
		Type:      samplers.CounterMetric,
	}}
	ddMetrics := ddSink.finalizeMetrics(metrics)
	assert.Equal(t, "rate", ddMetrics[0].MetricType, "Metric type should be rate")
	assert.Equal(t, float64(1.0), ddMetrics[0].Value[0][1], "Metric rate wasnt computed correctly")
}

func TestServerTags(t *testing.T) {
	ddSink := DatadogMetricSink{
		hostname: "somehostname",
		tags:     []string{"a:b", "c:d"},
		interval: 10,
	}

	metrics := []samplers.InterMetric{{
		Name:      "foo.bar.baz",
		Timestamp: time.Now().Unix(),
		Value:     float64(10),
		Tags:      []string{"gorch:frobble", "x:e"},
		Type:      samplers.CounterMetric,
	}}

	ddMetrics := ddSink.finalizeMetrics(metrics)
	assert.Equal(t, "somehostname", ddMetrics[0].Hostname, "Metric hostname uses argument")
	assert.Contains(t, ddMetrics[0].Tags, "a:b", "Tags should contain server tags")
}

func TestHostMagicTag(t *testing.T) {
	ddSink := DatadogMetricSink{
		hostname: "badhostname",
		tags:     []string{"a:b", "c:d"},
	}

	metrics := []samplers.InterMetric{{
		Name:      "foo.bar.baz",
		Timestamp: time.Now().Unix(),
		Value:     float64(10),
		Tags:      []string{"gorch:frobble", "host:abc123", "x:e"},
		Type:      samplers.CounterMetric,
	}}

	ddMetrics := ddSink.finalizeMetrics(metrics)
	assert.Equal(t, "abc123", ddMetrics[0].Hostname, "Metric hostname should be from tag")
	assert.NotContains(t, ddMetrics[0].Tags, "host:abc123", "Host tag should be removed")
	assert.Contains(t, ddMetrics[0].Tags, "x:e", "Last tag is still around")
}

func TestDeviceMagicTag(t *testing.T) {
	ddSink := DatadogMetricSink{
		hostname: "badhostname",
		tags:     []string{"a:b", "c:d"},
	}

	metrics := []samplers.InterMetric{{
		Name:      "foo.bar.baz",
		Timestamp: time.Now().Unix(),
		Value:     float64(10),
		Tags:      []string{"gorch:frobble", "device:abc123", "x:e"},
		Type:      samplers.CounterMetric,
	}}

	ddMetrics := ddSink.finalizeMetrics(metrics)
	assert.Equal(t, "abc123", ddMetrics[0].DeviceName, "Metric devicename should be from tag")
	assert.NotContains(t, ddMetrics[0].Tags, "device:abc123", "Host tag should be removed")
	assert.Contains(t, ddMetrics[0].Tags, "x:e", "Last tag is still around")
}

func TestNewDatadogSpanSinkConfig(t *testing.T) {
	// test the variables that have been renamed
	stats, _ := statsd.NewBuffered("localhost:1235", 1024)
	ddSink, err := NewDatadogSpanSink("http://example.com", 100, stats, &http.Client{}, nil, logrus.New())
	if err != nil {
		t.Fatal(err)
	}
	err = ddSink.Start(nil)
	if err != nil {
		t.Fatal(err)
	}

	assert.Equal(t, "http://example.com", ddSink.traceAddress)
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
)

type writeFile func(filename string, data []byte, perm os.FileMode) error

type Downloader struct {
	OutputDir    string
	RelativePath string
	Results      []Res
}

type Res struct {
	Data []byte
	Err  error
	Url  string
	Id   string
}

func (d *Downloader) ExtractId(url string) string {
	idReg := regexp.MustCompile(`https://drive.google.com/file/d/(\w+)/.*`)
	id := idReg.FindStringSubmatch(url)
	// didn't find a match
	if len(id) < 2 {
		return ""
	}
	return id[1]
}

func (d *Downloader) CreateRelPath(id string) string {
	return filepath.Join(d.RelativePath, id)
}
func (d *Downloader) CreateDestPath(id string) string {
	return filepath.Join(d.OutputDir, id)
}
func (d *Downloader) CreateTargetUrl(id string) string {
	return "https://googledrive.com/host/" + id
}

func (d *Downloader) Download(url string, origUrl string, id string, chanDown chan<- Res) {
	res, err := http.Get(url)
	defer res.Body.Close()
	data, err := ioutil.ReadAll(res.Body)
	chanDown <- Res{data, err, origUrl, id}
}

func (d *Downloader) WriteToDisk(destPath string, chanDown <-chan Res) {
	res := <-chanDown
	if res.Err != nil {
		res.Err = ioutil.WriteFile(destPath, res.Data, 0644)
	}
	d.Results = append(d.Results, res)
}

func (d *Downloader) RewriteUrlsInJson() {

}

func (d *Downloader) Run(assets map[string]Asset) error {
	var (
		err      error
		chanDown = make(chan Res, 5)
	)
	for k, _ := range assets {
		if id := d.ExtractId(k); id != "" {
			go d.Download(d.CreateTargetUrl(id), k, id, chanDown)
			go d.WriteToDisk(d.CreateDestPath(id), chanDown)
		}
	}

	for _, v := range d.Results {
		err = v.Err
	}

	return err
}

// ioutil.WriteFile

// if err != nil {
// 	d.Assets[k] = Asset{"", err}
// } else {
// 	d.Assets[k] = Asset{d.CreateRelPath(id), nil}
// }
<commit_msg>add json argument to rewriteurls method<commit_after>package main

import (
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
)

type writeFile func(filename string, data []byte, perm os.FileMode) error

type Downloader struct {
	OutputDir    string
	RelativePath string
	Results      []Res
}

type Res struct {
	Data []byte
	Err  error
	Url  string
	Id   string
}

func (d *Downloader) ExtractId(url string) string {
	idReg := regexp.MustCompile(`https://drive.google.com/file/d/(\w+)/.*`)
	id := idReg.FindStringSubmatch(url)
	// didn't find a match
	if len(id) < 2 {
		return ""
	}
	return id[1]
}

func (d *Downloader) CreateRelPath(id string) string {
	return filepath.Join(d.RelativePath, id)
}
func (d *Downloader) CreateDestPath(id string) string {
	return filepath.Join(d.OutputDir, id)
}
func (d *Downloader) CreateTargetUrl(id string) string {
	return "https://googledrive.com/host/" + id
}

func (d *Downloader) Download(url string, origUrl string, id string, chanDown chan<- Res) {
	res, err := http.Get(url)
	defer res.Body.Close()
	data, err := ioutil.ReadAll(res.Body)
	chanDown <- Res{data, err, origUrl, id}
}

func (d *Downloader) WriteToDisk(destPath string, chanDown <-chan Res) {
	res := <-chanDown
	if res.Err != nil {
		res.Err = ioutil.WriteFile(destPath, res.Data, 0644)
	}
	d.Results = append(d.Results, res)
}

func (d *Downloader) RewriteUrlsInJson(jsonData interface{}) {
	// d.Results
}

func (d *Downloader) Run(assets map[string]Asset) error {
	var (
		err      error
		chanDown = make(chan Res, 5)
	)
	for k, _ := range assets {
		if id := d.ExtractId(k); id != "" {
			go d.Download(d.CreateTargetUrl(id), k, id, chanDown)
			go d.WriteToDisk(d.CreateDestPath(id), chanDown)
		}
	}

	for _, v := range d.Results {
		err = v.Err
	}

	return err
}

// ioutil.WriteFile

// if err != nil {
// 	d.Assets[k] = Asset{"", err}
// } else {
// 	d.Assets[k] = Asset{d.CreateRelPath(id), nil}
// }
<|endoftext|>


<commit_before>package template

import (
	"bytes"
	"context"
	"fmt"
	"github.com/labstack/echo/v4"
	htmlTemplate "html/template"
	"net/http"
	"strings"
	textTemplate "text/template"
	"xorkevin.dev/governor"
)

type (
	// Template is a templating service
	Template interface {
		Execute(templateName string, data interface{}) ([]byte, error)
		ExecuteHTML(filename string, data interface{}) ([]byte, error)
	}

	Service interface {
		governor.Service
		Template
	}

	service struct {
		tt     *textTemplate.Template
		ht     *htmlTemplate.Template
		logger governor.Logger
	}
)

// New creates a new Template service
func New() Service {
	return &service{}
}

func (s *service) Register(r governor.ConfigRegistrar, jr governor.JobRegistrar) {
	r.SetDefault("dir", "templates")
}

func (s *service) Init(ctx context.Context, c governor.Config, r governor.ConfigReader, l governor.Logger, g *echo.Group) error {
	s.logger = l
	l = s.logger.WithData(map[string]string{
		"phase": "init",
	})
	templateDir := r.GetStr("dir")
	tt, err := textTemplate.ParseGlob(templateDir + "/*.txt")
	if err != nil {
		if err.Error() == fmt.Sprintf("text/template: pattern matches no files: %#q", r.GetStr("dir")+"/*.html") {
			l.Warn("no templates loaded", nil)
			tt = textTemplate.New("default")
		} else {
			return governor.NewError("Failed to load templates", http.StatusInternalServerError, err)
		}
	}
	s.tt = tt
	ht, err := htmlTemplate.ParseGlob(templateDir + "/*.html")
	if err != nil {
		if err.Error() == fmt.Sprintf("html/template: pattern matches no files: %#q", r.GetStr("dir")+"/*.html") {
			l.Warn("no templates loaded", nil)
			ht = htmlTemplate.New("default")
		} else {
			return governor.NewError("Failed to load templates", http.StatusInternalServerError, err)
		}
	}
	s.ht = ht

	if k := tt.DefinedTemplates(); k != "" {
		l.Info("loaded text templates", map[string]string{
			"templates": strings.TrimLeft(k, "; "),
		})
	}
	if k := ht.DefinedTemplates(); k != "" {
		l.Info("loaded html templates", map[string]string{
			"templates": strings.TrimLeft(k, "; "),
		})
	}
	return nil
}

func (s *service) Setup(req governor.ReqSetup) error {
	return nil
}

func (s *service) Start(ctx context.Context) error {
	return nil
}

func (s *service) Stop(ctx context.Context) {
}

func (s *service) Health() error {
	return nil
}

// Execute executes a template and returns the templated string
func (s *service) Execute(templateName string, data interface{}) ([]byte, error) {
	b := &bytes.Buffer{}
	if err := s.tt.ExecuteTemplate(b, templateName, data); err != nil {
		return nil, governor.NewError("Failed executing text template", http.StatusInternalServerError, err)
	}
	return b.Bytes(), nil
}

// ExecuteHTML executes an html template and returns the templated string
func (s *service) ExecuteHTML(templateName string, data interface{}) ([]byte, error) {
	b := &bytes.Buffer{}
	if err := s.ht.ExecuteTemplate(b, templateName, data); err != nil {
		return nil, governor.NewError("Failed executing html template", http.StatusInternalServerError, err)
	}
	return b.Bytes(), nil
}
<commit_msg>Fix template service init interface<commit_after>package template

import (
	"bytes"
	"context"
	"fmt"
	htmlTemplate "html/template"
	"net/http"
	"strings"
	textTemplate "text/template"
	"xorkevin.dev/governor"
)

type (
	// Template is a templating service
	Template interface {
		Execute(templateName string, data interface{}) ([]byte, error)
		ExecuteHTML(filename string, data interface{}) ([]byte, error)
	}

	Service interface {
		governor.Service
		Template
	}

	service struct {
		tt     *textTemplate.Template
		ht     *htmlTemplate.Template
		logger governor.Logger
	}
)

// New creates a new Template service
func New() Service {
	return &service{}
}

func (s *service) Register(r governor.ConfigRegistrar, jr governor.JobRegistrar) {
	r.SetDefault("dir", "templates")
}

func (s *service) Init(ctx context.Context, c governor.Config, r governor.ConfigReader, l governor.Logger, m governor.Router) error {
	s.logger = l
	l = s.logger.WithData(map[string]string{
		"phase": "init",
	})
	templateDir := r.GetStr("dir")
	tt, err := textTemplate.ParseGlob(templateDir + "/*.txt")
	if err != nil {
		if err.Error() == fmt.Sprintf("text/template: pattern matches no files: %#q", r.GetStr("dir")+"/*.html") {
			l.Warn("no templates loaded", nil)
			tt = textTemplate.New("default")
		} else {
			return governor.NewError("Failed to load templates", http.StatusInternalServerError, err)
		}
	}
	s.tt = tt
	ht, err := htmlTemplate.ParseGlob(templateDir + "/*.html")
	if err != nil {
		if err.Error() == fmt.Sprintf("html/template: pattern matches no files: %#q", r.GetStr("dir")+"/*.html") {
			l.Warn("no templates loaded", nil)
			ht = htmlTemplate.New("default")
		} else {
			return governor.NewError("Failed to load templates", http.StatusInternalServerError, err)
		}
	}
	s.ht = ht

	if k := tt.DefinedTemplates(); k != "" {
		l.Info("loaded text templates", map[string]string{
			"templates": strings.TrimLeft(k, "; "),
		})
	}
	if k := ht.DefinedTemplates(); k != "" {
		l.Info("loaded html templates", map[string]string{
			"templates": strings.TrimLeft(k, "; "),
		})
	}
	return nil
}

func (s *service) Setup(req governor.ReqSetup) error {
	return nil
}

func (s *service) Start(ctx context.Context) error {
	return nil
}

func (s *service) Stop(ctx context.Context) {
}

func (s *service) Health() error {
	return nil
}

// Execute executes a template and returns the templated string
func (s *service) Execute(templateName string, data interface{}) ([]byte, error) {
	b := &bytes.Buffer{}
	if err := s.tt.ExecuteTemplate(b, templateName, data); err != nil {
		return nil, governor.NewError("Failed executing text template", http.StatusInternalServerError, err)
	}
	return b.Bytes(), nil
}

// ExecuteHTML executes an html template and returns the templated string
func (s *service) ExecuteHTML(templateName string, data interface{}) ([]byte, error) {
	b := &bytes.Buffer{}
	if err := s.ht.ExecuteTemplate(b, templateName, data); err != nil {
		return nil, governor.NewError("Failed executing html template", http.StatusInternalServerError, err)
	}
	return b.Bytes(), nil
}
<|endoftext|>


<commit_before>package context

import (
	"go/build"
	"os"
	"path/filepath"
	"reflect"
	"testing"

	"github.com/neovim-go/vim"
	"golang.org/x/net/context"
)

var (
	cwd, _ = os.Getwd()

	projectRoot, _ = filepath.Abs(filepath.Join(cwd, "../../.."))
	testdata       = filepath.Join(projectRoot, "test", "testdata")
	testGoPath     = filepath.Join(testdata, "go")

	astdump     = filepath.Join(testGoPath, "src", "astdump")
	astdumpMain = filepath.Join(astdump, "astdump.go")
)

func TestNewContext(t *testing.T) {
	tests := []struct {
		name string
		want *Context
	}{
	// TODO: Add test cases.
	}
	for _, tt := range tests {
		if got := NewContext(); !reflect.DeepEqual(got, tt.want) {
			t.Errorf("%q. NewContext() = %v, want %v", tt.name, got, tt.want)
		}
	}
}

func TestContext_buildContext(t *testing.T) {
	type fields struct {
		Context context.Context
		Build   Build
		Errlist map[string][]*vim.QuickfixError
	}
	type args struct {
		p string
	}
	tests := []struct {
		name   string
		fields fields
		args   args
		want   build.Context
	}{
	// TODO: Add test cases.
	}
	for _, tt := range tests {
		ctxt := &Context{
			Context: tt.fields.Context,
			Build:   tt.fields.Build,
			Errlist: tt.fields.Errlist,
		}
		if got := ctxt.buildContext(tt.args.p); !reflect.DeepEqual(got, tt.want) {
			t.Errorf("%q. Context.buildContext(%v) = %v, want %v", tt.name, tt.args.p, got, tt.want)
		}
	}
}

func TestContext_SetContext(t *testing.T) {
	type fields struct {
		Context context.Context
		Build   Build
		Errlist map[string][]*vim.QuickfixError
	}
	type args struct {
		p string
	}
	tests := []struct {
		name   string
		fields fields
		args   args
		want   func()
	}{
	// TODO: Add test cases.
	}
	for _, tt := range tests {
		ctxt := &Context{
			Context: tt.fields.Context,
			Build:   tt.fields.Build,
			Errlist: tt.fields.Errlist,
		}
		if got := ctxt.SetContext(tt.args.p); !reflect.DeepEqual(got, tt.want) {
			t.Errorf("%q. Context.SetContext(%v) = %v, want %v", tt.name, tt.args.p, got, tt.want)
		}
	}
}
<commit_msg>test/context: add build.Default to buildContext argument<commit_after>package context

import (
	"go/build"
	"os"
	"path/filepath"
	"reflect"
	"testing"

	"github.com/neovim-go/vim"
	"golang.org/x/net/context"
)

var (
	cwd, _ = os.Getwd()

	projectRoot, _ = filepath.Abs(filepath.Join(cwd, "../../.."))
	testdata       = filepath.Join(projectRoot, "test", "testdata")
	testGoPath     = filepath.Join(testdata, "go")

	astdump     = filepath.Join(testGoPath, "src", "astdump")
	astdumpMain = filepath.Join(astdump, "astdump.go")
)

func TestNewContext(t *testing.T) {
	tests := []struct {
		name string
		want *Context
	}{
	// TODO: Add test cases.
	}
	for _, tt := range tests {
		if got := NewContext(); !reflect.DeepEqual(got, tt.want) {
			t.Errorf("%q. NewContext() = %v, want %v", tt.name, got, tt.want)
		}
	}
}

func TestContext_buildContext(t *testing.T) {
	type fields struct {
		Context context.Context
		Build   Build
		Errlist map[string][]*vim.QuickfixError
	}
	type args struct {
		p string
	}
	tests := []struct {
		name   string
		fields fields
		args   args
		want   build.Context
	}{
	// TODO: Add test cases.
	}
	for _, tt := range tests {
		ctxt := &Context{
			Context: tt.fields.Context,
			Build:   tt.fields.Build,
			Errlist: tt.fields.Errlist,
		}
		if got := ctxt.buildContext(tt.args.p, build.Default); !reflect.DeepEqual(got, tt.want) {
			t.Errorf("%q. Context.buildContext(%v) = %v, want %v", tt.name, tt.args.p, got, tt.want)
		}
	}
}

func TestContext_SetContext(t *testing.T) {
	type fields struct {
		Context context.Context
		Build   Build
		Errlist map[string][]*vim.QuickfixError
	}
	type args struct {
		p string
	}
	tests := []struct {
		name   string
		fields fields
		args   args
		want   func()
	}{
	// TODO: Add test cases.
	}
	for _, tt := range tests {
		ctxt := &Context{
			Context: tt.fields.Context,
			Build:   tt.fields.Build,
			Errlist: tt.fields.Errlist,
		}
		if got := ctxt.SetContext(tt.args.p); !reflect.DeepEqual(got, tt.want) {
			t.Errorf("%q. Context.SetContext(%v) = %v, want %v", tt.name, tt.args.p, got, tt.want)
		}
	}
}
<|endoftext|>


<commit_before>package portmapper

import (
	"github.com/dotcloud/docker/pkg/iptables"
	"github.com/dotcloud/docker/pkg/proxy"
	"net"
	"testing"
)

func init() {
	// override this func to mock out the proxy server
	newProxy = proxy.NewStubProxy
}

func reset() {
	chain = nil
	currentMappings = make(map[string]*mapping)
}

func TestSetIptablesChain(t *testing.T) {
	defer reset()

	c := &iptables.Chain{
		Name:   "TEST",
		Bridge: "192.168.1.1",
	}

	if chain != nil {
		t.Fatal("chain should be nil at init")
	}

	SetIptablesChain(c)
	if chain == nil {
		t.Fatal("chain should not be nil after set")
	}
}

func TestMapPorts(t *testing.T) {
	dstIp1 := net.ParseIP("192.168.0.1")
	dstIp2 := net.ParseIP("192.168.0.2")
	dstAddr1 := &net.TCPAddr{IP: dstIp1, Port: 80}
	dstAddr2 := &net.TCPAddr{IP: dstIp2, Port: 80}

	srcAddr1 := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.1")}
	srcAddr2 := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.2")}

	addrEqual := func(addr1, addr2 net.Addr) bool {
		return (addr1.Network() == addr2.Network()) && (addr1.String() == addr2.String())
	}

	if host, err := Map(srcAddr1, dstIp1, 80); err != nil {
		t.Fatalf("Failed to allocate port: %s", err)
	} else if !addrEqual(dstAddr1, host) {
		t.Fatalf("Incorrect mapping result: expected %s:%s, got %s:%s",
			dstAddr1.String(), dstAddr1.Network(), host.String(), host.Network())
	}

	if _, err := Map(srcAddr1, dstIp1, 80); err == nil {
		t.Fatalf("Port is in use - mapping should have failed")
	}

	if _, err := Map(srcAddr2, dstIp1, 80); err == nil {
		t.Fatalf("Port is in use - mapping should have failed")
	}

	if _, err := Map(srcAddr2, dstIp2, 80); err != nil {
		t.Fatalf("Failed to allocate port: %s", err)
	}

	if Unmap(dstAddr1) != nil {
		t.Fatalf("Failed to release port")
	}

	if Unmap(dstAddr2) != nil {
		t.Fatalf("Failed to release port")
	}

	if Unmap(dstAddr2) == nil {
		t.Fatalf("Port already released, but no error reported")
	}
}

func TestGetUDPKey(t *testing.T) {
	addr := &net.UDPAddr{IP: net.ParseIP("192.168.1.5"), Port: 53}

	key := getKey(addr)

	if expected := "192.168.1.5:53/udp"; key != expected {
		t.Fatalf("expected key %s got %s", expected, key)
	}
}

func TestGetTCPKey(t *testing.T) {
	addr := &net.TCPAddr{IP: net.ParseIP("192.168.1.5"), Port: 80}

	key := getKey(addr)

	if expected := "192.168.1.5:80/tcp"; key != expected {
		t.Fatalf("expected key %s got %s", expected, key)
	}
}

func TestGetUDPIPAndPort(t *testing.T) {
	addr := &net.UDPAddr{IP: net.ParseIP("192.168.1.5"), Port: 53}

	ip, port := getIPAndPort(addr)
	if expected := "192.168.1.5"; ip.String() != expected {
		t.Fatalf("expected ip %s got %s", expected, ip)
	}

	if ep := 53; port != ep {
		t.Fatalf("expected port %d got %d", ep, port)
	}
}
<commit_msg>portmapper: unit tests for remap problem<commit_after>package portmapper

import (
	"github.com/dotcloud/docker/daemon/networkdriver/portallocator"
	"github.com/dotcloud/docker/pkg/iptables"
	"github.com/dotcloud/docker/pkg/proxy"
	"net"
	"testing"
)

func init() {
	// override this func to mock out the proxy server
	newProxy = proxy.NewStubProxy
}

func reset() {
	chain = nil
	currentMappings = make(map[string]*mapping)
}

func TestSetIptablesChain(t *testing.T) {
	defer reset()

	c := &iptables.Chain{
		Name:   "TEST",
		Bridge: "192.168.1.1",
	}

	if chain != nil {
		t.Fatal("chain should be nil at init")
	}

	SetIptablesChain(c)
	if chain == nil {
		t.Fatal("chain should not be nil after set")
	}
}

func TestMapPorts(t *testing.T) {
	dstIp1 := net.ParseIP("192.168.0.1")
	dstIp2 := net.ParseIP("192.168.0.2")
	dstAddr1 := &net.TCPAddr{IP: dstIp1, Port: 80}
	dstAddr2 := &net.TCPAddr{IP: dstIp2, Port: 80}

	srcAddr1 := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.1")}
	srcAddr2 := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.2")}

	addrEqual := func(addr1, addr2 net.Addr) bool {
		return (addr1.Network() == addr2.Network()) && (addr1.String() == addr2.String())
	}

	if host, err := Map(srcAddr1, dstIp1, 80); err != nil {
		t.Fatalf("Failed to allocate port: %s", err)
	} else if !addrEqual(dstAddr1, host) {
		t.Fatalf("Incorrect mapping result: expected %s:%s, got %s:%s",
			dstAddr1.String(), dstAddr1.Network(), host.String(), host.Network())
	}

	if _, err := Map(srcAddr1, dstIp1, 80); err == nil {
		t.Fatalf("Port is in use - mapping should have failed")
	}

	if _, err := Map(srcAddr2, dstIp1, 80); err == nil {
		t.Fatalf("Port is in use - mapping should have failed")
	}

	if _, err := Map(srcAddr2, dstIp2, 80); err != nil {
		t.Fatalf("Failed to allocate port: %s", err)
	}

	if Unmap(dstAddr1) != nil {
		t.Fatalf("Failed to release port")
	}

	if Unmap(dstAddr2) != nil {
		t.Fatalf("Failed to release port")
	}

	if Unmap(dstAddr2) == nil {
		t.Fatalf("Port already released, but no error reported")
	}
}

func TestGetUDPKey(t *testing.T) {
	addr := &net.UDPAddr{IP: net.ParseIP("192.168.1.5"), Port: 53}

	key := getKey(addr)

	if expected := "192.168.1.5:53/udp"; key != expected {
		t.Fatalf("expected key %s got %s", expected, key)
	}
}

func TestGetTCPKey(t *testing.T) {
	addr := &net.TCPAddr{IP: net.ParseIP("192.168.1.5"), Port: 80}

	key := getKey(addr)

	if expected := "192.168.1.5:80/tcp"; key != expected {
		t.Fatalf("expected key %s got %s", expected, key)
	}
}

func TestGetUDPIPAndPort(t *testing.T) {
	addr := &net.UDPAddr{IP: net.ParseIP("192.168.1.5"), Port: 53}

	ip, port := getIPAndPort(addr)
	if expected := "192.168.1.5"; ip.String() != expected {
		t.Fatalf("expected ip %s got %s", expected, ip)
	}

	if ep := 53; port != ep {
		t.Fatalf("expected port %d got %d", ep, port)
	}
}

func TestMapAllPortsSingleInterface(t *testing.T) {
	dstIp1 := net.ParseIP("0.0.0.0")
	srcAddr1 := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.1")}

	hosts := []net.Addr{}
	var host net.Addr
	var err error

	defer func() {
		for _, val := range hosts {
			Unmap(val)
		}
	}()

	for i := 0; i < 10; i++ {
		for i := portallocator.BeginPortRange; i < portallocator.EndPortRange; i++ {
			if host, err = Map(srcAddr1, dstIp1, 0); err != nil {
				t.Fatal(err)
			}

			hosts = append(hosts, host)
		}

		if _, err := Map(srcAddr1, dstIp1, portallocator.BeginPortRange); err == nil {
			t.Fatal("Port %d should be bound but is not", portallocator.BeginPortRange)
		}

		for _, val := range hosts {
			if err := Unmap(val); err != nil {
				t.Fatal(err)
			}
		}

		hosts = []net.Addr{}
	}
}
<|endoftext|>


<commit_before>package driver

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/mail"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/blang/semver"
	"github.com/concourse/semver-resource/version"
)

var gitRepoDir string
var privateKeyPath string
var netRcPath string

var ErrEncryptedKey = errors.New("private keys with passphrases are not supported")

func init() {
	gitRepoDir = filepath.Join(os.TempDir(), "semver-git-repo")
	privateKeyPath = filepath.Join(os.TempDir(), "private-key")
	netRcPath = filepath.Join(os.Getenv("HOME"), ".netrc")
}

type GitDriver struct {
	InitialVersion semver.Version

	URI           string
	Branch        string
	PrivateKey    string
	Username      string
	Password      string
	File          string
	GitUser       string
	Depth         string
	CommitMessage string
}

func (driver *GitDriver) Bump(bump version.Bump) (semver.Version, error) {
	err := driver.setUpAuth()
	if err != nil {
		return semver.Version{}, err
	}

	err = driver.setUserInfo()
	if err != nil {
		return semver.Version{}, err
	}

	var newVersion semver.Version

	for {
		err = driver.setUpRepo()
		if err != nil {
			return semver.Version{}, err
		}

		currentVersion, exists, err := driver.readVersion()
		if err != nil {
			return semver.Version{}, err
		}

		if !exists {
			currentVersion = driver.InitialVersion
		}

		newVersion = bump.Apply(currentVersion)

		wrote, err := driver.writeVersion(newVersion)
		if wrote {
			break
		}
	}

	return newVersion, nil
}

func (driver *GitDriver) Set(newVersion semver.Version) error {
	err := driver.setUpAuth()
	if err != nil {
		return err
	}

	err = driver.setUserInfo()
	if err != nil {
		return err
	}

	for {
		err = driver.setUpRepo()
		if err != nil {
			return err
		}

		wrote, err := driver.writeVersion(newVersion)
		if err != nil {
			return err
		}

		if wrote {
			break
		}
	}

	return nil
}

func (driver *GitDriver) Check(cursor *semver.Version) ([]semver.Version, error) {
	err := driver.setUpAuth()
	if err != nil {
		return nil, err
	}

	err = driver.setUpRepo()
	if err != nil {
		return nil, err
	}

	currentVersion, exists, err := driver.readVersion()
	if err != nil {
		return nil, err
	}

	if !exists {
		return []semver.Version{driver.InitialVersion}, nil
	}

	if cursor == nil || currentVersion.GTE(*cursor) {
		return []semver.Version{currentVersion}, nil
	}

	return []semver.Version{}, nil
}

func (driver *GitDriver) setUpRepo() error {
	_, err := os.Stat(gitRepoDir)
	if err != nil {
		gitClone := exec.Command("git", "clone", driver.URI, "--branch", driver.Branch)
		if len(driver.Depth) > 0 {
			gitClone.Args = append(gitClone.Args, "--depth", driver.Depth)
		}
		gitClone.Args = append(gitClone.Args, "--single-branch", gitRepoDir)
		gitClone.Stdout = os.Stderr
		gitClone.Stderr = os.Stderr
		if err := gitClone.Run(); err != nil {
			return err
		}
	} else {
		gitFetch := exec.Command("git", "fetch", "origin", driver.Branch)
		gitFetch.Dir = gitRepoDir
		gitFetch.Stdout = os.Stderr
		gitFetch.Stderr = os.Stderr
		if err := gitFetch.Run(); err != nil {
			return err
		}
	}

	gitCheckout := exec.Command("git", "reset", "--hard", "origin/"+driver.Branch)
	gitCheckout.Dir = gitRepoDir
	gitCheckout.Stdout = os.Stderr
	gitCheckout.Stderr = os.Stderr
	if err := gitCheckout.Run(); err != nil {
		return err
	}

	return nil
}

func (driver *GitDriver) setUpAuth() error {
	_, err := os.Stat(netRcPath)
	if err != nil {
		if !os.IsNotExist(err) {
			return err
		}
	} else {
		err := os.Remove(netRcPath)
		if err != nil {
			return err
		}
	}

	if len(driver.PrivateKey) > 0 {
		err := driver.setUpKey()
		if err != nil {
			return err
		}
	}

	if len(driver.Username) > 0 && len(driver.Password) > 0 {
		err := driver.setUpUsernamePassword()
		if err != nil {
			return err
		}
	}

	return nil
}

func (driver *GitDriver) setUpKey() error {
	_, err := os.Stat(privateKeyPath)
	if err != nil {
		if os.IsNotExist(err) {
			err := ioutil.WriteFile(privateKeyPath, []byte(driver.PrivateKey), 0600)
			if err != nil {
				return err
			}
		} else {
			return err
		}
	}

	if isPrivateKeyEncrypted(privateKeyPath) {
		return ErrEncryptedKey
	}

	return os.Setenv("GIT_SSH_COMMAND", "ssh -o StrictHostKeyChecking=no -i "+privateKeyPath)
}

func isPrivateKeyEncrypted(path string) bool {
	passphrase := ``
	cmd := exec.Command(`ssh-keygen`, `-y`, `-f`, path, `-P`, passphrase)
	err := cmd.Run()

	return err != nil
}

func (driver *GitDriver) setUpUsernamePassword() error {
	_, err := os.Stat(netRcPath)
	if err != nil {
		if os.IsNotExist(err) {
			content := fmt.Sprintf("default login %s password %s", driver.Username, driver.Password)
			err := ioutil.WriteFile(netRcPath, []byte(content), 0600)
			if err != nil {
				return err
			}
		} else {
			return err
		}
	}

	return nil
}

func (driver *GitDriver) setUserInfo() error {
	if len(driver.GitUser) == 0 {
		return nil
	}

	e, err := mail.ParseAddress(driver.GitUser)
	if err != nil {
		return err
	}

	if len(e.Name) > 0 {
		gitName := exec.Command("git", "config", "--global", "user.name", e.Name)
		gitName.Stdout = os.Stderr
		gitName.Stderr = os.Stderr
		if err := gitName.Run(); err != nil {
			return err
		}
	}

	gitEmail := exec.Command("git", "config", "--global", "user.email", e.Address)
	gitEmail.Stdout = os.Stderr
	gitEmail.Stderr = os.Stderr
	if err := gitEmail.Run(); err != nil {
		return err
	}
	return nil
}

func (driver *GitDriver) readVersion() (semver.Version, bool, error) {
	var currentVersionStr string
	versionFile, err := os.Open(filepath.Join(gitRepoDir, driver.File))
	if err != nil {
		if os.IsNotExist(err) {
			return semver.Version{}, false, nil
		}

		return semver.Version{}, false, err
	}

	defer versionFile.Close()

	_, err = fmt.Fscanf(versionFile, "%s", &currentVersionStr)
	if err != nil {
		return semver.Version{}, false, err
	}

	currentVersion, err := semver.Parse(currentVersionStr)
	if err != nil {
		return semver.Version{}, false, err
	}

	return currentVersion, true, nil
}

const nothingToCommitString = "nothing to commit"
const falsePushString = "Everything up-to-date"
const pushRejectedString = "[rejected]"
const pushRemoteRejectedString = "[remote rejected]"

func (driver *GitDriver) writeVersion(newVersion semver.Version) (bool, error) {
	err := ioutil.WriteFile(filepath.Join(gitRepoDir, driver.File), []byte(newVersion.String()+"\n"), 0644)
	if err != nil {
		return false, err
	}

	gitAdd := exec.Command("git", "add", driver.File)
	gitAdd.Dir = gitRepoDir
	gitAdd.Stdout = os.Stderr
	gitAdd.Stderr = os.Stderr
	if err := gitAdd.Run(); err != nil {
		return false, err
	}
	var commitMessage string
	if driver.CommitMessage == "" {
		commitMessage = "bump to " + newVersion.String()
	} else {
		commitMessage = strings.Replace(driver.CommitMessage, "%version%", newVersion.String(), -1)
		commitMessage = strings.Replace(commitMessage, "%file%", driver.File, -1)
	}

	gitCommit := exec.Command("git", "commit", "-m", commitMessage)
	gitCommit.Dir = gitRepoDir

	commitOutput, err := gitCommit.CombinedOutput()

	if strings.Contains(string(commitOutput), nothingToCommitString) {
		return true, nil
	}

	if err != nil {
		os.Stderr.Write(commitOutput)
		return false, err
	}

	gitPush := exec.Command("git", "push", "origin", "HEAD:"+driver.Branch)
	gitPush.Dir = gitRepoDir

	pushOutput, err := gitPush.CombinedOutput()

	if strings.Contains(string(pushOutput), falsePushString) {
		return false, nil
	}

	if strings.Contains(string(pushOutput), pushRejectedString) {
		return false, nil
	}

	if strings.Contains(string(pushOutput), pushRemoteRejectedString) {
		return false, nil
	}

	if err != nil {
		os.Stderr.Write(pushOutput)
		return false, err
	}

	return true, nil
}
<commit_msg>Add additional logging to git driver<commit_after>package driver

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/mail"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/blang/semver"
	"github.com/concourse/semver-resource/version"
)

var gitRepoDir string
var privateKeyPath string
var netRcPath string

var ErrEncryptedKey = errors.New("private keys with passphrases are not supported")

func init() {
	gitRepoDir = filepath.Join(os.TempDir(), "semver-git-repo")
	privateKeyPath = filepath.Join(os.TempDir(), "private-key")
	netRcPath = filepath.Join(os.Getenv("HOME"), ".netrc")
}

type GitDriver struct {
	InitialVersion semver.Version

	URI           string
	Branch        string
	PrivateKey    string
	Username      string
	Password      string
	File          string
	GitUser       string
	Depth         string
	CommitMessage string
}

func (driver *GitDriver) Bump(bump version.Bump) (semver.Version, error) {
	err := driver.setUpAuth()
	if err != nil {
		return semver.Version{}, err
	}

	err = driver.setUserInfo()
	if err != nil {
		return semver.Version{}, err
	}

	var newVersion semver.Version

	for {
		err = driver.setUpRepo()
		if err != nil {
			return semver.Version{}, err
		}

		currentVersion, exists, err := driver.readVersion()
		if err != nil {
			return semver.Version{}, err
		}

		if !exists {
			currentVersion = driver.InitialVersion
		}

		newVersion = bump.Apply(currentVersion)

		wrote, err := driver.writeVersion(newVersion)
		if wrote {
			break
		}
	}

	return newVersion, nil
}

func (driver *GitDriver) Set(newVersion semver.Version) error {
	err := driver.setUpAuth()
	if err != nil {
		return err
	}

	err = driver.setUserInfo()
	if err != nil {
		return err
	}

	for {
		err = driver.setUpRepo()
		if err != nil {
			return err
		}

		wrote, err := driver.writeVersion(newVersion)
		if err != nil {
			return err
		}

		if wrote {
			break
		}
	}

	return nil
}

func (driver *GitDriver) Check(cursor *semver.Version) ([]semver.Version, error) {
	err := driver.setUpAuth()
	if err != nil {
		return nil, err
	}

	err = driver.setUpRepo()
	if err != nil {
		return nil, err
	}

	currentVersion, exists, err := driver.readVersion()
	if err != nil {
		return nil, err
	}

	if !exists {
		return []semver.Version{driver.InitialVersion}, nil
	}

	if cursor == nil || currentVersion.GTE(*cursor) {
		return []semver.Version{currentVersion}, nil
	}

	return []semver.Version{}, nil
}

func (driver *GitDriver) setUpRepo() error {
	_, err := os.Stat(gitRepoDir)
	if err != nil {
		gitClone := exec.Command("git", "clone", driver.URI, "--branch", driver.Branch)
		if len(driver.Depth) > 0 {
			gitClone.Args = append(gitClone.Args, "--depth", driver.Depth)
		}
		gitClone.Args = append(gitClone.Args, "--single-branch", gitRepoDir)
		gitClone.Stdout = os.Stderr
		gitClone.Stderr = os.Stderr
		if err := gitClone.Run(); err != nil {
			return err
		}
	} else {
		gitFetch := exec.Command("git", "fetch", "origin", driver.Branch)
		gitFetch.Dir = gitRepoDir
		gitFetch.Stdout = os.Stderr
		gitFetch.Stderr = os.Stderr
		if err := gitFetch.Run(); err != nil {
			return err
		}
	}

	gitCheckout := exec.Command("git", "reset", "--hard", "origin/"+driver.Branch)
	gitCheckout.Dir = gitRepoDir
	gitCheckout.Stdout = os.Stderr
	gitCheckout.Stderr = os.Stderr
	if err := gitCheckout.Run(); err != nil {
		return err
	}

	return nil
}

func (driver *GitDriver) setUpAuth() error {
	_, err := os.Stat(netRcPath)
	if err != nil {
		if !os.IsNotExist(err) {
			return err
		}
	} else {
		err := os.Remove(netRcPath)
		if err != nil {
			return err
		}
	}

	if len(driver.PrivateKey) > 0 {
		err := driver.setUpKey()
		if err != nil {
			return err
		}
	}

	if len(driver.Username) > 0 && len(driver.Password) > 0 {
		err := driver.setUpUsernamePassword()
		if err != nil {
			return err
		}
	}

	return nil
}

func (driver *GitDriver) setUpKey() error {
	_, err := os.Stat(privateKeyPath)
	if err != nil {
		if os.IsNotExist(err) {
			err := ioutil.WriteFile(privateKeyPath, []byte(driver.PrivateKey), 0600)
			if err != nil {
				return err
			}
		} else {
			return err
		}
	}

	if isPrivateKeyEncrypted(privateKeyPath) {
		return ErrEncryptedKey
	}

	return os.Setenv("GIT_SSH_COMMAND", "ssh -o StrictHostKeyChecking=no -i "+privateKeyPath)
}

func isPrivateKeyEncrypted(path string) bool {
	passphrase := ``
	cmd := exec.Command(`ssh-keygen`, `-y`, `-f`, path, `-P`, passphrase)
	err := cmd.Run()

	return err != nil
}

func (driver *GitDriver) setUpUsernamePassword() error {
	_, err := os.Stat(netRcPath)
	if err != nil {
		if os.IsNotExist(err) {
			content := fmt.Sprintf("default login %s password %s", driver.Username, driver.Password)
			err := ioutil.WriteFile(netRcPath, []byte(content), 0600)
			if err != nil {
				return err
			}
		} else {
			return err
		}
	}

	return nil
}

func (driver *GitDriver) setUserInfo() error {
	if len(driver.GitUser) == 0 {
		return nil
	}

	e, err := mail.ParseAddress(driver.GitUser)
	if err != nil {
		return err
	}

	if len(e.Name) > 0 {
		gitName := exec.Command("git", "config", "--global", "user.name", e.Name)
		gitName.Stdout = os.Stderr
		gitName.Stderr = os.Stderr
		if err := gitName.Run(); err != nil {
			return err
		}
	}

	gitEmail := exec.Command("git", "config", "--global", "user.email", e.Address)
	gitEmail.Stdout = os.Stderr
	gitEmail.Stderr = os.Stderr
	if err := gitEmail.Run(); err != nil {
		return err
	}
	return nil
}

func (driver *GitDriver) readVersion() (semver.Version, bool, error) {
	var currentVersionStr string
	versionFile, err := os.Open(filepath.Join(gitRepoDir, driver.File))
	if err != nil {
		if os.IsNotExist(err) {
			return semver.Version{}, false, nil
		}

		return semver.Version{}, false, err
	}

	defer versionFile.Close()

	_, err = fmt.Fscanf(versionFile, "%s", &currentVersionStr)
	if err != nil {
		return semver.Version{}, false, err
	}

	currentVersion, err := semver.Parse(currentVersionStr)
	if err != nil {
		return semver.Version{}, false, err
	}

	return currentVersion, true, nil
}

const nothingToCommitString = "nothing to commit"
const falsePushString = "Everything up-to-date"
const pushRejectedString = "[rejected]"
const pushRemoteRejectedString = "[remote rejected]"

func (driver *GitDriver) writeVersion(newVersion semver.Version) (bool, error) {
	err := ioutil.WriteFile(filepath.Join(gitRepoDir, driver.File), []byte(newVersion.String()+"\n"), 0644)
	if err != nil {
		return false, err
	}

	gitAdd := exec.Command("git", "add", driver.File)
	gitAdd.Dir = gitRepoDir
	gitAdd.Stdout = os.Stderr
	gitAdd.Stderr = os.Stderr
	if err := gitAdd.Run(); err != nil {
		return false, err
	}
	var commitMessage string
	if driver.CommitMessage == "" {
		commitMessage = "bump to " + newVersion.String()
	} else {
		commitMessage = strings.Replace(driver.CommitMessage, "%version%", newVersion.String(), -1)
		commitMessage = strings.Replace(commitMessage, "%file%", driver.File, -1)
	}

	gitCommit := exec.Command("git", "commit", "-m", commitMessage)
	gitCommit.Dir = gitRepoDir

	commitOutput, err := gitCommit.CombinedOutput()

	if strings.Contains(string(commitOutput), nothingToCommitString) {
		os.Stderr.Write([]byte("Nothing to commit, skipping version push\n"))
		return true, nil
	}

	if err != nil {
		os.Stderr.Write(commitOutput)
		return false, err
	}

	gitPush := exec.Command("git", "push", "origin", "HEAD:"+driver.Branch)
	gitPush.Dir = gitRepoDir

	pushOutput, err := gitPush.CombinedOutput()

	if strings.Contains(string(pushOutput), falsePushString) ||
		strings.Contains(string(pushOutput), pushRejectedString) ||
		strings.Contains(string(pushOutput), pushRemoteRejectedString) {
		os.Stderr.Write(pushOutput)
		return false, nil
	}

	if err != nil {
		os.Stderr.Write(pushOutput)
		return false, err
	}

	return true, nil
}
<|endoftext|>


<commit_before>/*
   Copyright The containerd 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 main

import (
	"context"
	"fmt"
	"strings"
	"syscall"
	"time"

	"github.com/containerd/containerd"
	"github.com/containerd/containerd/cio"
	"github.com/containerd/containerd/oci"
	specs "github.com/opencontainers/runtime-spec/specs-go"
	"github.com/sirupsen/logrus"
)

type execWorker struct {
	worker
}

func (w *execWorker) exec(ctx, tctx context.Context) {
	defer func() {
		w.wg.Done()
		logrus.Infof("worker %d finished", w.id)
	}()
	id := fmt.Sprintf("exec-container-%d", w.id)
	c, err := w.client.NewContainer(ctx, id,
		containerd.WithNewSnapshot(id, w.image),
		containerd.WithSnapshotter(w.snapshotter),
		containerd.WithNewSpec(oci.WithImageConfig(w.image), oci.WithUsername("games"), oci.WithProcessArgs("sleep", "30d")),
	)
	if err != nil {
		logrus.WithError(err).Error("create exec container")
		return
	}
	defer c.Delete(ctx, containerd.WithSnapshotCleanup)

	task, err := c.NewTask(ctx, cio.NullIO)
	if err != nil {
		logrus.WithError(err).Error("create exec container's task")
		return
	}
	defer task.Delete(ctx, containerd.WithProcessKill)

	statusC, err := task.Wait(ctx)
	if err != nil {
		logrus.WithError(err).Error("wait exec container's task")
		return
	}
	spec, err := c.Spec(ctx)
	if err != nil {
		logrus.WithError(err).Error("failed to get spec")
		return
	}

	pspec := spec.Process
	pspec.Args = []string{"true"}

	for {
		select {
		case <-tctx.Done():
			if err := task.Kill(ctx, syscall.SIGKILL); err != nil {
				logrus.WithError(err).Error("kill exec container's task")
			}
			<-statusC
			return
		default:
		}

		w.count++
		id := w.getID()
		logrus.Debugf("starting exec %s", id)
		start := time.Now()

		if err := w.runExec(ctx, task, id, pspec); err != nil {
			if err != context.DeadlineExceeded ||
				!strings.Contains(err.Error(), context.DeadlineExceeded.Error()) {
				w.failures++
				logrus.WithError(err).Errorf("running exec %s", id)
				errCounter.WithValues(err.Error()).Inc()
			}
			continue
		}
		// only log times are success so we don't scew the results from failures that go really fast
		execTimer.WithValues(w.commit).UpdateSince(start)
	}
}

func (w *execWorker) runExec(ctx context.Context, task containerd.Task, id string, spec *specs.Process) (err error) {
	process, err := task.Exec(ctx, id, spec, cio.NullIO)
	if err != nil {
		return err
	}
	defer func() {
		if _, derr := process.Delete(ctx, containerd.WithProcessKill); err == nil {
			err = derr
		}
	}()
	statusC, err := process.Wait(ctx)
	if err != nil {
		return err
	}
	if err := process.Start(ctx); err != nil {
		return err
	}
	status := <-statusC
	_, _, err = status.Result()
	if err != nil {
		if err == context.DeadlineExceeded || err == context.Canceled {
			return nil
		}
		w.failures++
		errCounter.WithValues(err.Error()).Inc()
	}
	return nil
}
<commit_msg>containerd-stress: start task ctr before starting execs<commit_after>/*
   Copyright The containerd 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 main

import (
	"context"
	"fmt"
	"strings"
	"syscall"
	"time"

	"github.com/containerd/containerd"
	"github.com/containerd/containerd/cio"
	"github.com/containerd/containerd/oci"
	specs "github.com/opencontainers/runtime-spec/specs-go"
	"github.com/sirupsen/logrus"
)

type execWorker struct {
	worker
}

func (w *execWorker) exec(ctx, tctx context.Context) {
	defer func() {
		w.wg.Done()
		logrus.Infof("worker %d finished", w.id)
	}()
	id := fmt.Sprintf("exec-container-%d", w.id)
	c, err := w.client.NewContainer(ctx, id,
		containerd.WithNewSnapshot(id, w.image),
		containerd.WithSnapshotter(w.snapshotter),
		containerd.WithNewSpec(oci.WithImageConfig(w.image), oci.WithUsername("games"), oci.WithProcessArgs("sleep", "30d")),
	)
	if err != nil {
		logrus.WithError(err).Error("create exec container")
		return
	}
	defer c.Delete(ctx, containerd.WithSnapshotCleanup)

	task, err := c.NewTask(ctx, cio.NullIO)
	if err != nil {
		logrus.WithError(err).Error("create exec container's task")
		return
	}
	defer task.Delete(ctx, containerd.WithProcessKill)

	statusC, err := task.Wait(ctx)
	if err != nil {
		logrus.WithError(err).Error("wait exec container's task")
		return
	}

	if err := task.Start(ctx); err != nil {
		logrus.WithError(err).Error("exec container start failure")
		return
	}

	spec, err := c.Spec(ctx)
	if err != nil {
		logrus.WithError(err).Error("failed to get spec")
		return
	}

	pspec := spec.Process
	pspec.Args = []string{"true"}

	for {
		select {
		case <-tctx.Done():
			if err := task.Kill(ctx, syscall.SIGKILL); err != nil {
				logrus.WithError(err).Error("kill exec container's task")
			}
			<-statusC
			return
		default:
		}

		w.count++
		id := w.getID()
		logrus.Debugf("starting exec %s", id)
		start := time.Now()

		if err := w.runExec(ctx, task, id, pspec); err != nil {
			if err != context.DeadlineExceeded ||
				!strings.Contains(err.Error(), context.DeadlineExceeded.Error()) {
				w.failures++
				logrus.WithError(err).Errorf("running exec %s", id)
				errCounter.WithValues(err.Error()).Inc()
			}
			continue
		}
		// only log times are success so we don't scew the results from failures that go really fast
		execTimer.WithValues(w.commit).UpdateSince(start)
	}
}

func (w *execWorker) runExec(ctx context.Context, task containerd.Task, id string, spec *specs.Process) (err error) {
	process, err := task.Exec(ctx, id, spec, cio.NullIO)
	if err != nil {
		return err
	}
	defer func() {
		if _, derr := process.Delete(ctx, containerd.WithProcessKill); err == nil {
			err = derr
		}
	}()
	statusC, err := process.Wait(ctx)
	if err != nil {
		return err
	}
	if err := process.Start(ctx); err != nil {
		return err
	}
	status := <-statusC
	_, _, err = status.Result()
	if err != nil {
		if err == context.DeadlineExceeded || err == context.Canceled {
			return nil
		}
		w.failures++
		errCounter.WithValues(err.Error()).Inc()
	}
	return nil
}
<|endoftext|>


<commit_before>package entrypoint

import (
	"context"
	"fmt"
	"log"
	"net"
	"net/http"
	"net/http/httputil"
	"net/url"
	"time"

	"github.com/datawire/ambassador/pkg/acp"
	"github.com/datawire/ambassador/pkg/debug"
)

func handleCheckAlive(w http.ResponseWriter, r *http.Request, ambwatch *acp.AmbassadorWatcher) {
	// The liveness check needs to explicitly try to talk to Envoy...
	ambwatch.FetchEnvoyReady(r.Context())

	// ...then check if the watcher says we're alive.
	ok := ambwatch.IsAlive()

	if ok {
		w.Write([]byte("Ambassador is alive and well\n"))
	} else {
		http.Error(w, "Ambassador is not alive\n", http.StatusServiceUnavailable)
	}
}

func handleCheckReady(w http.ResponseWriter, r *http.Request, ambwatch *acp.AmbassadorWatcher) {
	// The readiness check needs to explicitly try to talk to Envoy, too. Why?
	// Because if you have a pod configured with only the readiness check but
	// not the liveness check, and we don't try to talk to Envoy here, then we
	// will never ever attempt to talk to Envoy at all, Envoy will never be
	// declared alive, and we'll never consider Ambassador ready.
	ambwatch.FetchEnvoyReady(r.Context())

	ok := ambwatch.IsReady()

	if ok {
		w.Write([]byte("Ambassador is ready and waiting\n"))
	} else {
		http.Error(w, "Ambassador is not ready\n", http.StatusServiceUnavailable)
	}
}

func healthCheckHandler(ctx context.Context, ambwatch *acp.AmbassadorWatcher) {
	dbg := debug.FromContext(ctx)

	// We need to do some HTTP stuff by hand to catch the readiness and liveness
	// checks here, but forward everything else to diagd.
	sm := http.NewServeMux()

	// Handle the liveness check and the readiness check directly, by handing them
	// off to our functions.

	livenessTimer := dbg.Timer("check_alive")
	sm.HandleFunc("/ambassador/v0/check_alive",
		livenessTimer.TimedHandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			handleCheckAlive(w, r, ambwatch)
		}))

	readinessTimer := dbg.Timer("check_ready")
	sm.HandleFunc("/ambassador/v0/check_ready",
		readinessTimer.TimedHandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			handleCheckReady(w, r, ambwatch)
		}))

	// Serve any debug info from the golang codebase.
	sm.Handle("/debug", dbg)

	// For everything else, use a ReverseProxy to forward it to diagd.
	//
	// diagdOrigin is where diagd is listening.
	diagdOrigin, _ := url.Parse("http://127.0.0.1:8004/")

	// This reverseProxy is dirt simple: use a director function to
	// swap the scheme and host of our request for the ones from the
	// diagdOrigin. Leave everything else (notably including the path)
	// alone.
	reverseProxy := &httputil.ReverseProxy{
		Director: func(req *http.Request) {
			req.URL.Scheme = diagdOrigin.Scheme
			req.URL.Host = diagdOrigin.Host

			// If this request is coming from localhost, tell diagd about that.
			if acp.HostPortIsLocal(req.RemoteAddr) {
				req.Header.Set("X-Ambassador-Diag-IP", "127.0.0.1")
			}
		},
	}

	// Finally, use the reverseProxy to handle anything coming in on
	// the magic catchall path.
	sm.HandleFunc("/", reverseProxy.ServeHTTP)

	// Create a listener by hand, so that we can listen on TCP v4. If we don't
	// explicitly say "tcp4" here, we seem to listen _only_ on v6, and Bad Things
	// Happen.
	//
	// XXX Why, exactly, is this? That's a lovely question -- we _should_ be OK
	// here on a proper dualstack system, but apparently we don't have a proper
	// dualstack system? It's quite bizarre, but Kubernetes won't become ready
	// without this.
	//
	// XXX In fact, should we set up another Listener for v6??
	listener, err := net.Listen("tcp4", ":8877")

	if err != nil {
		// Uh whut. This REALLY should not be possible -- we should be cranking
		// up at boot time and nothing, but nothing, should already be bound on
		// port 8877.
		panic(fmt.Errorf("could not listen on TCP port 8877: %v", err))
	}

	s := &http.Server{
		Addr:    ":8877",
		Handler: sm,
	}

	// Given that, all that's left is to fire up a server using our
	// router.
	go func() {
		log.Fatal(s.Serve(listener))
	}()

	// ...then wait for a shutdown signal.
	<-ctx.Done()

	tctx, tcancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer tcancel()

	err = s.Shutdown(tctx)

	if err != nil {
		panic(err)
	}
}
<commit_msg>(from AES) Merge pull request #2035 from datawire/rhs/debug-pprof<commit_after>package entrypoint

import (
	"context"
	"fmt"
	"log"
	"net"
	"net/http"
	"net/http/httputil"
	"net/http/pprof"
	"net/url"
	"time"

	"github.com/datawire/ambassador/pkg/acp"
	"github.com/datawire/ambassador/pkg/debug"
)

func handleCheckAlive(w http.ResponseWriter, r *http.Request, ambwatch *acp.AmbassadorWatcher) {
	// The liveness check needs to explicitly try to talk to Envoy...
	ambwatch.FetchEnvoyReady(r.Context())

	// ...then check if the watcher says we're alive.
	ok := ambwatch.IsAlive()

	if ok {
		w.Write([]byte("Ambassador is alive and well\n"))
	} else {
		http.Error(w, "Ambassador is not alive\n", http.StatusServiceUnavailable)
	}
}

func handleCheckReady(w http.ResponseWriter, r *http.Request, ambwatch *acp.AmbassadorWatcher) {
	// The readiness check needs to explicitly try to talk to Envoy, too. Why?
	// Because if you have a pod configured with only the readiness check but
	// not the liveness check, and we don't try to talk to Envoy here, then we
	// will never ever attempt to talk to Envoy at all, Envoy will never be
	// declared alive, and we'll never consider Ambassador ready.
	ambwatch.FetchEnvoyReady(r.Context())

	ok := ambwatch.IsReady()

	if ok {
		w.Write([]byte("Ambassador is ready and waiting\n"))
	} else {
		http.Error(w, "Ambassador is not ready\n", http.StatusServiceUnavailable)
	}
}

func healthCheckHandler(ctx context.Context, ambwatch *acp.AmbassadorWatcher) {
	dbg := debug.FromContext(ctx)

	// We need to do some HTTP stuff by hand to catch the readiness and liveness
	// checks here, but forward everything else to diagd.
	sm := http.NewServeMux()

	// Handle the liveness check and the readiness check directly, by handing them
	// off to our functions.

	livenessTimer := dbg.Timer("check_alive")
	sm.HandleFunc("/ambassador/v0/check_alive",
		livenessTimer.TimedHandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			handleCheckAlive(w, r, ambwatch)
		}))

	readinessTimer := dbg.Timer("check_ready")
	sm.HandleFunc("/ambassador/v0/check_ready",
		readinessTimer.TimedHandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			handleCheckReady(w, r, ambwatch)
		}))

	// Serve any debug info from the golang codebase.
	sm.Handle("/debug", dbg)

	// Serve pprof endpoints to aid in live debugging.
	sm.HandleFunc("/debug/pprof/", pprof.Index)

	// For everything else, use a ReverseProxy to forward it to diagd.
	//
	// diagdOrigin is where diagd is listening.
	diagdOrigin, _ := url.Parse("http://127.0.0.1:8004/")

	// This reverseProxy is dirt simple: use a director function to
	// swap the scheme and host of our request for the ones from the
	// diagdOrigin. Leave everything else (notably including the path)
	// alone.
	reverseProxy := &httputil.ReverseProxy{
		Director: func(req *http.Request) {
			req.URL.Scheme = diagdOrigin.Scheme
			req.URL.Host = diagdOrigin.Host

			// If this request is coming from localhost, tell diagd about that.
			if acp.HostPortIsLocal(req.RemoteAddr) {
				req.Header.Set("X-Ambassador-Diag-IP", "127.0.0.1")
			}
		},
	}

	// Finally, use the reverseProxy to handle anything coming in on
	// the magic catchall path.
	sm.HandleFunc("/", reverseProxy.ServeHTTP)

	// Create a listener by hand, so that we can listen on TCP v4. If we don't
	// explicitly say "tcp4" here, we seem to listen _only_ on v6, and Bad Things
	// Happen.
	//
	// XXX Why, exactly, is this? That's a lovely question -- we _should_ be OK
	// here on a proper dualstack system, but apparently we don't have a proper
	// dualstack system? It's quite bizarre, but Kubernetes won't become ready
	// without this.
	//
	// XXX In fact, should we set up another Listener for v6??
	listener, err := net.Listen("tcp4", ":8877")

	if err != nil {
		// Uh whut. This REALLY should not be possible -- we should be cranking
		// up at boot time and nothing, but nothing, should already be bound on
		// port 8877.
		panic(fmt.Errorf("could not listen on TCP port 8877: %v", err))
	}

	s := &http.Server{
		Addr:    ":8877",
		Handler: sm,
	}

	// Given that, all that's left is to fire up a server using our
	// router.
	go func() {
		log.Fatal(s.Serve(listener))
	}()

	// ...then wait for a shutdown signal.
	<-ctx.Done()

	tctx, tcancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer tcancel()

	err = s.Shutdown(tctx)

	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package gateway

import (
	"fmt"
	"os"
	"sync"
	"sync/atomic"
	"time"

	log "github.com/funkygao/log4go"
)

// AccessLogger is a daily rotating/unblocking logger to record access log.
type AccessLogger struct {
	filename string
	mu       sync.Mutex
	fd       *os.File

	discarded uint64
	lines     chan []byte
	stop      chan struct{}
}

func NewAccessLogger(fn string, poolSize int) *AccessLogger {
	return &AccessLogger{
		filename: fn,
		lines:    make(chan []byte, poolSize),
	}
}

func (this *AccessLogger) Log(line []byte) {
	select {
	case this.lines <- line:
	default:
		// too busy, silently discard it
		total := atomic.AddUint64(&this.discarded, 1)
		if total%1000 == 0 {
			log.Warn("access logger discarded: %d", total)
		}
	}
}

func (this *AccessLogger) Start() error {
	var err error
	if this.fd, err = os.OpenFile(this.filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0660); err != nil {
		return err
	}

	this.stop = make(chan struct{})

	go func() {
		tick := time.NewTicker(time.Second)
		defer tick.Stop()

		var lastDay int
		for {
			select {
			case <-this.stop:
				return

			case t := <-tick.C:
				this.mu.Lock()
				if this.fd != nil &&
					t.Day() != lastDay &&
					t.Hour() == 0 &&
					t.Minute() >= 0 &&
					t.Second() >= 0 {
					this.doRotate()
					lastDay = t.Day() // only once a day
				}
				this.mu.Unlock()

			case line, ok := <-this.lines:
				// FIXME at 00:00:00, buffer might overflow and lose log entry
				if !ok {
					// stopped
					return
				}

				if this.fd != nil {
					this.fd.Write(line)
				}
			}
		}
	}()

	return nil
}

func (this *AccessLogger) doRotate() {
	var fname string
	_, err := os.Lstat(this.filename)
	if err == nil {
		// file exists, find a empty slot
		num := 1
		for ; err == nil && num <= 999; num++ {
			fname = this.filename + fmt.Sprintf(".%03d", num)
			_, err = os.Lstat(fname)
		}

		if err == nil {
			log.Error("Access logger unable to rotate, 30 years passed?")
			return
		}
	}

	this.fd.Close()
	this.fd = nil

	// if fd does not close, after rename, fd.Write happens
	// content will be written to new file
	err = os.Rename(this.filename, fname)
	if err != nil {
		log.Error("rename %s->%s: %v", this.filename, fname)
		return
	}

	if this.fd, err = os.OpenFile(this.filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0660); err != nil {
		log.Error("open(%s): %s", this.filename, err)
	}

}

func (this *AccessLogger) Stop() {
	this.mu.Lock()
	defer this.mu.Unlock()

	if this.stop != nil {
		close(this.stop)
	} else {
		// call Stop when not Started
	}

	if this.fd != nil {
		this.fd.Close()
		this.fd = nil
	}
}
<commit_msg>solve race conditions for access logger<commit_after>package gateway

import (
	"fmt"
	"os"
	"sync/atomic"
	"time"

	log "github.com/funkygao/log4go"
)

// AccessLogger is a daily rotating/unblocking logger to record access log.
type AccessLogger struct {
	filename  string
	fd        *os.File
	lines     chan []byte
	discarded uint64
	stopped   chan struct{}
}

func NewAccessLogger(fn string, poolSize int) *AccessLogger {
	return &AccessLogger{
		filename: fn,
		lines:    make(chan []byte, poolSize),
		stopped:  make(chan struct{}),
	}
}

// Caution: NEVER call Log after Stop is called.
func (this *AccessLogger) Log(line []byte) {
	select {
	case this.lines <- line:
	default:
		// too busy, silently discard it
		total := atomic.AddUint64(&this.discarded, 1)
		if total%1000 == 0 {
			log.Warn("access logger discarded: %d", total)
		}
	}
}

func (this *AccessLogger) Start() error {
	var err error
	if this.fd, err = os.OpenFile(this.filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0660); err != nil {
		return err
	}

	go func() {
		tick := time.NewTicker(time.Second)
		defer tick.Stop()

		var lastDay int
		for {
			select {
			case t := <-tick.C:
				if this.fd != nil &&
					t.Day() != lastDay &&
					t.Hour() == 0 &&
					t.Minute() >= 0 &&
					t.Second() >= 0 {
					this.doRotate()
					lastDay = t.Day() // only once a day
				}

			case line, ok := <-this.lines:
				if !ok {
					// Stop() called, all inflight log lines flushed
					if this.fd != nil {
						this.fd.Close() // auto flush
						this.fd = nil
					}

					close(this.stopped)
					return
				}

				if this.fd != nil {
					this.fd.Write(line)
				}

			}
		}
	}()

	return nil
}

func (this *AccessLogger) doRotate() {
	var fname string
	_, err := os.Lstat(this.filename)
	if err == nil {
		// file exists, find a empty slot
		num := 1
		for ; err == nil && num <= 999; num++ {
			fname = this.filename + fmt.Sprintf(".%03d", num)
			_, err = os.Lstat(fname)
		}

		if err == nil {
			log.Error("Access logger unable to rotate, 30 years passed?")
			return
		}
	}

	this.fd.Close()
	this.fd = nil

	// if fd does not close, after rename, fd.Write happens
	// content will be written to new file
	err = os.Rename(this.filename, fname)
	if err != nil {
		log.Error("rename %s->%s: %v", this.filename, fname)
		return
	}

	if this.fd, err = os.OpenFile(this.filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0660); err != nil {
		log.Error("open(%s): %s", this.filename, err)
	}

}

func (this *AccessLogger) Stop() {
	close(this.lines)
	<-this.stopped
}

func (this *AccessLogger) Discarded() uint64 {
	return atomic.LoadUint64(&this.discarded)
}
<|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 features

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

	utilfeature "k8s.io/apiserver/pkg/util/feature"
	"k8s.io/kubernetes/pkg/util/version"
)

const (
	// HighAvailability is alpha in v1.9
	HighAvailability = "HighAvailability"

	// CoreDNS is alpha in v1.9
	CoreDNS = "CoreDNS"

	// SelfHosting is alpha in v1.8 and v1.9
	SelfHosting = "SelfHosting"

	// StoreCertsInSecrets is alpha in v1.8 and v1.9
	StoreCertsInSecrets = "StoreCertsInSecrets"

	// DynamicKubeletConfig is alpha in v1.9
	DynamicKubeletConfig = "DynamicKubeletConfig"

	// Auditing is beta in 1.8
	Auditing = "Auditing"
)

var v190 = version.MustParseSemantic("v1.9.0-alpha.1")

// InitFeatureGates are the default feature gates for the init command
var InitFeatureGates = FeatureList{
	SelfHosting:         {FeatureSpec: utilfeature.FeatureSpec{Default: false, PreRelease: utilfeature.Alpha}},
	StoreCertsInSecrets: {FeatureSpec: utilfeature.FeatureSpec{Default: false, PreRelease: utilfeature.Alpha}},
	// We don't want to advertise this feature gate exists in v1.9 to avoid confusion as it is not yet working
	HighAvailability:     {FeatureSpec: utilfeature.FeatureSpec{Default: false, PreRelease: utilfeature.Alpha}, MinimumVersion: v190, HiddenInHelpText: true},
	CoreDNS:              {FeatureSpec: utilfeature.FeatureSpec{Default: false, PreRelease: utilfeature.Beta}, MinimumVersion: v190},
	DynamicKubeletConfig: {FeatureSpec: utilfeature.FeatureSpec{Default: false, PreRelease: utilfeature.Alpha}, MinimumVersion: v190},
	Auditing:             {FeatureSpec: utilfeature.FeatureSpec{Default: false, PreRelease: utilfeature.Alpha}},
}

// Feature represents a feature being gated
type Feature struct {
	utilfeature.FeatureSpec
	MinimumVersion   *version.Version
	HiddenInHelpText bool
}

// FeatureList represents a list of feature gates
type FeatureList map[string]Feature

// ValidateVersion ensures that a feature gate list is compatible with the chosen kubernetes version
func ValidateVersion(allFeatures FeatureList, requestedFeatures map[string]bool, requestedVersion string) error {
	if requestedVersion == "" {
		return nil
	}
	parsedExpVersion, err := version.ParseSemantic(requestedVersion)
	if err != nil {
		return fmt.Errorf("Error parsing version %s: %v", requestedVersion, err)
	}
	for k := range requestedFeatures {
		if minVersion := allFeatures[k].MinimumVersion; minVersion != nil {
			if !parsedExpVersion.AtLeast(minVersion) {
				return fmt.Errorf(
					"the requested kubernetes version (%s) is incompatible with the %s feature gate, which needs %s as a minimum",
					requestedVersion, k, minVersion)
			}
		}
	}
	return nil
}

// Enabled indicates whether a feature name has been enabled
func Enabled(featureList map[string]bool, featureName string) bool {
	return featureList[string(featureName)]
}

// Supports indicates whether a feature name is supported on the given
// feature set
func Supports(featureList FeatureList, featureName string) bool {
	for k := range featureList {
		if featureName == string(k) {
			return true
		}
	}
	return false
}

// Keys returns a slice of feature names for a given feature set
func Keys(featureList FeatureList) []string {
	var list []string
	for k := range featureList {
		list = append(list, string(k))
	}
	return list
}

// KnownFeatures returns a slice of strings describing the FeatureList features.
func KnownFeatures(f *FeatureList) []string {
	var known []string
	for k, v := range *f {
		if v.HiddenInHelpText {
			continue
		}

		pre := ""
		if v.PreRelease != utilfeature.GA {
			pre = fmt.Sprintf("%s - ", v.PreRelease)
		}
		known = append(known, fmt.Sprintf("%s=true|false (%sdefault=%t)", k, pre, v.Default))
	}
	sort.Strings(known)
	return known
}

// NewFeatureGate parses a string of the form "key1=value1,key2=value2,..." into a
// map[string]bool of known keys or returns an error.
func NewFeatureGate(f *FeatureList, value string) (map[string]bool, error) {
	featureGate := map[string]bool{}
	for _, s := range strings.Split(value, ",") {
		if len(s) == 0 {
			continue
		}

		arr := strings.SplitN(s, "=", 2)
		if len(arr) != 2 {
			return nil, fmt.Errorf("missing bool value for feature-gate key:%s", s)
		}

		k := strings.TrimSpace(arr[0])
		v := strings.TrimSpace(arr[1])

		if !Supports(*f, k) {
			return nil, fmt.Errorf("unrecognized feature-gate key: %s", k)
		}

		boolValue, err := strconv.ParseBool(v)
		if err != nil {
			return nil, fmt.Errorf("invalid value %v for feature-gate key: %s, use true|false instead", v, k)
		}
		featureGate[k] = boolValue
	}

	ResolveFeatureGateDependencies(featureGate)

	return featureGate, nil
}

// ResolveFeatureGateDependencies resolve dependencies between feature gates
func ResolveFeatureGateDependencies(featureGate map[string]bool) {

	// if StoreCertsInSecrets enabled, SelfHosting should enabled
	if Enabled(featureGate, StoreCertsInSecrets) {
		featureGate[SelfHosting] = true
	}

	// if HighAvailability enabled, both StoreCertsInSecrets and SelfHosting should enabled
	if Enabled(featureGate, HighAvailability) && !Enabled(featureGate, StoreCertsInSecrets) {
		featureGate[SelfHosting] = true
		featureGate[StoreCertsInSecrets] = true
	}
}
<commit_msg>bump coredns to GA in kubeadm<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 features

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

	utilfeature "k8s.io/apiserver/pkg/util/feature"
	"k8s.io/kubernetes/pkg/util/version"
)

const (
	// HighAvailability is alpha in v1.9
	HighAvailability = "HighAvailability"

	// CoreDNS is alpha in v1.9
	CoreDNS = "CoreDNS"

	// SelfHosting is alpha in v1.8 and v1.9
	SelfHosting = "SelfHosting"

	// StoreCertsInSecrets is alpha in v1.8 and v1.9
	StoreCertsInSecrets = "StoreCertsInSecrets"

	// DynamicKubeletConfig is alpha in v1.9
	DynamicKubeletConfig = "DynamicKubeletConfig"

	// Auditing is beta in 1.8
	Auditing = "Auditing"
)

var v190 = version.MustParseSemantic("v1.9.0-alpha.1")

// InitFeatureGates are the default feature gates for the init command
var InitFeatureGates = FeatureList{
	SelfHosting:         {FeatureSpec: utilfeature.FeatureSpec{Default: false, PreRelease: utilfeature.Alpha}},
	StoreCertsInSecrets: {FeatureSpec: utilfeature.FeatureSpec{Default: false, PreRelease: utilfeature.Alpha}},
	// We don't want to advertise this feature gate exists in v1.9 to avoid confusion as it is not yet working
	HighAvailability:     {FeatureSpec: utilfeature.FeatureSpec{Default: false, PreRelease: utilfeature.Alpha}, MinimumVersion: v190, HiddenInHelpText: true},
	CoreDNS:              {FeatureSpec: utilfeature.FeatureSpec{Default: false, PreRelease: utilfeature.GA}, MinimumVersion: v190},
	DynamicKubeletConfig: {FeatureSpec: utilfeature.FeatureSpec{Default: false, PreRelease: utilfeature.Alpha}, MinimumVersion: v190},
	Auditing:             {FeatureSpec: utilfeature.FeatureSpec{Default: false, PreRelease: utilfeature.Alpha}},
}

// Feature represents a feature being gated
type Feature struct {
	utilfeature.FeatureSpec
	MinimumVersion   *version.Version
	HiddenInHelpText bool
}

// FeatureList represents a list of feature gates
type FeatureList map[string]Feature

// ValidateVersion ensures that a feature gate list is compatible with the chosen kubernetes version
func ValidateVersion(allFeatures FeatureList, requestedFeatures map[string]bool, requestedVersion string) error {
	if requestedVersion == "" {
		return nil
	}
	parsedExpVersion, err := version.ParseSemantic(requestedVersion)
	if err != nil {
		return fmt.Errorf("Error parsing version %s: %v", requestedVersion, err)
	}
	for k := range requestedFeatures {
		if minVersion := allFeatures[k].MinimumVersion; minVersion != nil {
			if !parsedExpVersion.AtLeast(minVersion) {
				return fmt.Errorf(
					"the requested kubernetes version (%s) is incompatible with the %s feature gate, which needs %s as a minimum",
					requestedVersion, k, minVersion)
			}
		}
	}
	return nil
}

// Enabled indicates whether a feature name has been enabled
func Enabled(featureList map[string]bool, featureName string) bool {
	return featureList[string(featureName)]
}

// Supports indicates whether a feature name is supported on the given
// feature set
func Supports(featureList FeatureList, featureName string) bool {
	for k := range featureList {
		if featureName == string(k) {
			return true
		}
	}
	return false
}

// Keys returns a slice of feature names for a given feature set
func Keys(featureList FeatureList) []string {
	var list []string
	for k := range featureList {
		list = append(list, string(k))
	}
	return list
}

// KnownFeatures returns a slice of strings describing the FeatureList features.
func KnownFeatures(f *FeatureList) []string {
	var known []string
	for k, v := range *f {
		if v.HiddenInHelpText {
			continue
		}

		pre := ""
		if v.PreRelease != utilfeature.GA {
			pre = fmt.Sprintf("%s - ", v.PreRelease)
		}
		known = append(known, fmt.Sprintf("%s=true|false (%sdefault=%t)", k, pre, v.Default))
	}
	sort.Strings(known)
	return known
}

// NewFeatureGate parses a string of the form "key1=value1,key2=value2,..." into a
// map[string]bool of known keys or returns an error.
func NewFeatureGate(f *FeatureList, value string) (map[string]bool, error) {
	featureGate := map[string]bool{}
	for _, s := range strings.Split(value, ",") {
		if len(s) == 0 {
			continue
		}

		arr := strings.SplitN(s, "=", 2)
		if len(arr) != 2 {
			return nil, fmt.Errorf("missing bool value for feature-gate key:%s", s)
		}

		k := strings.TrimSpace(arr[0])
		v := strings.TrimSpace(arr[1])

		if !Supports(*f, k) {
			return nil, fmt.Errorf("unrecognized feature-gate key: %s", k)
		}

		boolValue, err := strconv.ParseBool(v)
		if err != nil {
			return nil, fmt.Errorf("invalid value %v for feature-gate key: %s, use true|false instead", v, k)
		}
		featureGate[k] = boolValue
	}

	ResolveFeatureGateDependencies(featureGate)

	return featureGate, nil
}

// ResolveFeatureGateDependencies resolve dependencies between feature gates
func ResolveFeatureGateDependencies(featureGate map[string]bool) {

	// if StoreCertsInSecrets enabled, SelfHosting should enabled
	if Enabled(featureGate, StoreCertsInSecrets) {
		featureGate[SelfHosting] = true
	}

	// if HighAvailability enabled, both StoreCertsInSecrets and SelfHosting should enabled
	if Enabled(featureGate, HighAvailability) && !Enabled(featureGate, StoreCertsInSecrets) {
		featureGate[SelfHosting] = true
		featureGate[StoreCertsInSecrets] = true
	}
}
<|endoftext|>