<commit_before>package datadog

import (
	"net"
	"reflect"
	"testing"

	"github.com/armon/go-metrics"
)

var EmptyTags []metrics.Label

const (
	DogStatsdAddr    = "127.0.0.1:7254"
	HostnameEnabled  = true
	HostnameDisabled = false
	TestHostname     = "test_hostname"
)

func MockGetHostname() string {
	return TestHostname
}

var ParseKeyTests = []struct {
	KeyToParse        []string
	Tags              []metrics.Label
	PropagateHostname bool
	ExpectedKey       []string
	ExpectedTags      []metrics.Label
}{
	{[]string{"a", MockGetHostname(), "b", "c"}, EmptyTags, HostnameDisabled, []string{"a", "b", "c"}, EmptyTags},
	{[]string{"a", "b", "c"}, EmptyTags, HostnameDisabled, []string{"a", "b", "c"}, EmptyTags},
	{[]string{"a", "b", "c"}, EmptyTags, HostnameEnabled, []string{"a", "b", "c"}, []metrics.Label{{"host", MockGetHostname()}}},
}

var FlattenKeyTests = []struct {
	KeyToFlatten []string
	Expected     string
}{
	{[]string{"a", "b", "c"}, "a.b.c"},
	{[]string{"spaces must", "flatten", "to", "underscores"}, "spaces_must.flatten.to.underscores"},
}

var MetricSinkTests = []struct {
	Method            string
	Metric            []string
	Value             interface{}
	Tags              []metrics.Label
	PropagateHostname bool
	Expected          string
}{
	{"SetGauge", []string{"foo", "bar"}, float32(42), EmptyTags, HostnameDisabled, "foo.bar:42.000000|g"},
	{"SetGauge", []string{"foo", "bar", "baz"}, float32(42), EmptyTags, HostnameDisabled, "foo.bar.baz:42.000000|g"},
	{"AddSample", []string{"sample", "thing"}, float32(4), EmptyTags, HostnameDisabled, "sample.thing:4.000000|ms"},
	{"IncrCounter", []string{"count", "me"}, float32(3), EmptyTags, HostnameDisabled, "count.me:3|c"},

	{"SetGauge", []string{"foo", "baz"}, float32(42), []metrics.Label{{"my_tag", ""}}, HostnameDisabled, "foo.baz:42.000000|g|#my_tag"},
	{"SetGauge", []string{"foo", "baz"}, float32(42), []metrics.Label{{"my tag", "my_value"}}, HostnameDisabled, "foo.baz:42.000000|g|#my_tag:my_value"},
	{"SetGauge", []string{"foo", "bar"}, float32(42), []metrics.Label{{"my_tag", "my_value"}, {"other_tag", "other_value"}}, HostnameDisabled, "foo.bar:42.000000|g|#my_tag:my_value,other_tag:other_value"},
	{"SetGauge", []string{"foo", "bar"}, float32(42), []metrics.Label{{"my_tag", "my_value"}, {"other_tag", "other_value"}}, HostnameEnabled, "foo.bar:42.000000|g|#my_tag:my_value,other_tag:other_value,host:test_hostname"},
}

func mockNewDogStatsdSink(addr string, labels []metrics.Label, tagWithHostname bool) *DogStatsdSink {
	dog, _ := NewDogStatsdSink(addr, MockGetHostname())
	_, tags := dog.getFlatkeyAndCombinedLabels(nil, labels)
	dog.SetTags(tags)
	if tagWithHostname {
		dog.EnableHostNamePropagation()
	}

	return dog
}

func setupTestServerAndBuffer(t *testing.T) (*net.UDPConn, []byte) {
	udpAddr, err := net.ResolveUDPAddr("udp", DogStatsdAddr)
	if err != nil {
		t.Fatal(err)
	}
	server, err := net.ListenUDP("udp", udpAddr)
	if err != nil {
		t.Fatal(err)
	}
	return server, make([]byte, 1024)
}

func TestParseKey(t *testing.T) {
	for _, tt := range ParseKeyTests {
		dog := mockNewDogStatsdSink(DogStatsdAddr, tt.Tags, tt.PropagateHostname)
		key, tags := dog.parseKey(tt.KeyToParse)

		if !reflect.DeepEqual(key, tt.ExpectedKey) {
			t.Fatalf("Key Parsing failed for %v", tt.KeyToParse)
		}

		if !reflect.DeepEqual(tags, tt.ExpectedTags) {
			t.Fatalf("Tag Parsing Failed for %v, %v != %v", tt.KeyToParse, tags, tt.ExpectedTags)
		}
	}
}

func TestFlattenKey(t *testing.T) {
	dog := mockNewDogStatsdSink(DogStatsdAddr, EmptyTags, HostnameDisabled)
	for _, tt := range FlattenKeyTests {
		if !reflect.DeepEqual(dog.flattenKey(tt.KeyToFlatten), tt.Expected) {
			t.Fatalf("Flattening %v failed", tt.KeyToFlatten)
		}
	}
}

func TestMetricSink(t *testing.T) {
	server, buf := setupTestServerAndBuffer(t)
	defer server.Close()

	for _, tt := range MetricSinkTests {
		dog := mockNewDogStatsdSink(DogStatsdAddr, tt.Tags, tt.PropagateHostname)
		method := reflect.ValueOf(dog).MethodByName(tt.Method)
		method.Call([]reflect.Value{
			reflect.ValueOf(tt.Metric),
			reflect.ValueOf(tt.Value)})
		assertServerMatchesExpected(t, server, buf, tt.Expected)
	}
}

func TestTaggableMetrics(t *testing.T) {
	server, buf := setupTestServerAndBuffer(t)
	defer server.Close()

	dog := mockNewDogStatsdSink(DogStatsdAddr, EmptyTags, HostnameDisabled)

	dog.AddSampleWithLabels([]string{"sample", "thing"}, float32(4), []metrics.Label{{"tagkey", "tagvalue"}})
	assertServerMatchesExpected(t, server, buf, "sample.thing:4.000000|ms|#tagkey:tagvalue")

	dog.SetGaugeWithLabels([]string{"sample", "thing"}, float32(4), []metrics.Label{{"tagkey", "tagvalue"}})
	assertServerMatchesExpected(t, server, buf, "sample.thing:4.000000|g|#tagkey:tagvalue")

	dog.IncrCounterWithLabels([]string{"sample", "thing"}, float32(4), []metrics.Label{{"tagkey", "tagvalue"}})
	assertServerMatchesExpected(t, server, buf, "sample.thing:4|c|#tagkey:tagvalue")

	dog = mockNewDogStatsdSink(DogStatsdAddr, []metrics.Label{{Name: "global"}}, HostnameEnabled) // with hostname, global tags
	dog.IncrCounterWithLabels([]string{"sample", "thing"}, float32(4), []metrics.Label{{"tagkey", "tagvalue"}})
	assertServerMatchesExpected(t, server, buf, "sample.thing:4|c|#global,tagkey:tagvalue,host:test_hostname")
}

func assertServerMatchesExpected(t *testing.T, server *net.UDPConn, buf []byte, expected string) {
	n, _ := server.Read(buf)
	msg := buf[:n]
	if string(msg) != expected {
		t.Fatalf("Line %s does not match expected: %s", string(msg), expected)
	}
}
<commit_msg>Fix datadog test failures<commit_after>package datadog

import (
	"net"
	"reflect"
	"testing"

	"github.com/armon/go-metrics"
)

var EmptyTags []metrics.Label

const (
	DogStatsdAddr    = "127.0.0.1:7254"
	HostnameEnabled  = true
	HostnameDisabled = false
	TestHostname     = "test_hostname"
)

func MockGetHostname() string {
	return TestHostname
}

var ParseKeyTests = []struct {
	KeyToParse        []string
	Tags              []metrics.Label
	PropagateHostname bool
	ExpectedKey       []string
	ExpectedTags      []metrics.Label
}{
	{[]string{"a", MockGetHostname(), "b", "c"}, EmptyTags, HostnameDisabled, []string{"a", "b", "c"}, EmptyTags},
	{[]string{"a", "b", "c"}, EmptyTags, HostnameDisabled, []string{"a", "b", "c"}, EmptyTags},
	{[]string{"a", "b", "c"}, EmptyTags, HostnameEnabled, []string{"a", "b", "c"}, []metrics.Label{{"host", MockGetHostname()}}},
}

var FlattenKeyTests = []struct {
	KeyToFlatten []string
	Expected     string
}{
	{[]string{"a", "b", "c"}, "a.b.c"},
	{[]string{"spaces must", "flatten", "to", "underscores"}, "spaces_must.flatten.to.underscores"},
}

var MetricSinkTests = []struct {
	Method            string
	Metric            []string
	Value             interface{}
	Tags              []metrics.Label
	PropagateHostname bool
	Expected          string
}{
	{"SetGauge", []string{"foo", "bar"}, float32(42), EmptyTags, HostnameDisabled, "foo.bar:42|g"},
	{"SetGauge", []string{"foo", "bar", "baz"}, float32(42), EmptyTags, HostnameDisabled, "foo.bar.baz:42|g"},
	{"AddSample", []string{"sample", "thing"}, float32(4), EmptyTags, HostnameDisabled, "sample.thing:4.000000|ms"},
	{"IncrCounter", []string{"count", "me"}, float32(3), EmptyTags, HostnameDisabled, "count.me:3|c"},

	{"SetGauge", []string{"foo", "baz"}, float32(42), []metrics.Label{{"my_tag", ""}}, HostnameDisabled, "foo.baz:42|g|#my_tag"},
	{"SetGauge", []string{"foo", "baz"}, float32(42), []metrics.Label{{"my tag", "my_value"}}, HostnameDisabled, "foo.baz:42|g|#my_tag:my_value"},
	{"SetGauge", []string{"foo", "bar"}, float32(42), []metrics.Label{{"my_tag", "my_value"}, {"other_tag", "other_value"}}, HostnameDisabled, "foo.bar:42|g|#my_tag:my_value,other_tag:other_value"},
	{"SetGauge", []string{"foo", "bar"}, float32(42), []metrics.Label{{"my_tag", "my_value"}, {"other_tag", "other_value"}}, HostnameEnabled, "foo.bar:42|g|#my_tag:my_value,other_tag:other_value,host:test_hostname"},
}

func mockNewDogStatsdSink(addr string, labels []metrics.Label, tagWithHostname bool) *DogStatsdSink {
	dog, _ := NewDogStatsdSink(addr, MockGetHostname())
	_, tags := dog.getFlatkeyAndCombinedLabels(nil, labels)
	dog.SetTags(tags)
	if tagWithHostname {
		dog.EnableHostNamePropagation()
	}

	return dog
}

func setupTestServerAndBuffer(t *testing.T) (*net.UDPConn, []byte) {
	udpAddr, err := net.ResolveUDPAddr("udp", DogStatsdAddr)
	if err != nil {
		t.Fatal(err)
	}
	server, err := net.ListenUDP("udp", udpAddr)
	if err != nil {
		t.Fatal(err)
	}
	return server, make([]byte, 1024)
}

func TestParseKey(t *testing.T) {
	for _, tt := range ParseKeyTests {
		dog := mockNewDogStatsdSink(DogStatsdAddr, tt.Tags, tt.PropagateHostname)
		key, tags := dog.parseKey(tt.KeyToParse)

		if !reflect.DeepEqual(key, tt.ExpectedKey) {
			t.Fatalf("Key Parsing failed for %v", tt.KeyToParse)
		}

		if !reflect.DeepEqual(tags, tt.ExpectedTags) {
			t.Fatalf("Tag Parsing Failed for %v, %v != %v", tt.KeyToParse, tags, tt.ExpectedTags)
		}
	}
}

func TestFlattenKey(t *testing.T) {
	dog := mockNewDogStatsdSink(DogStatsdAddr, EmptyTags, HostnameDisabled)
	for _, tt := range FlattenKeyTests {
		if !reflect.DeepEqual(dog.flattenKey(tt.KeyToFlatten), tt.Expected) {
			t.Fatalf("Flattening %v failed", tt.KeyToFlatten)
		}
	}
}

func TestMetricSink(t *testing.T) {
	server, buf := setupTestServerAndBuffer(t)
	defer server.Close()

	for _, tt := range MetricSinkTests {
		t.Run(tt.Method, func(t *testing.T) {
			dog := mockNewDogStatsdSink(DogStatsdAddr, tt.Tags, tt.PropagateHostname)
			method := reflect.ValueOf(dog).MethodByName(tt.Method)
			method.Call([]reflect.Value{
				reflect.ValueOf(tt.Metric),
				reflect.ValueOf(tt.Value)})
			assertServerMatchesExpected(t, server, buf, tt.Expected)
		})
	}
}

func TestTaggableMetrics(t *testing.T) {
	server, buf := setupTestServerAndBuffer(t)
	defer server.Close()

	dog := mockNewDogStatsdSink(DogStatsdAddr, EmptyTags, HostnameDisabled)

	dog.AddSampleWithLabels([]string{"sample", "thing"}, float32(4), []metrics.Label{{"tagkey", "tagvalue"}})
	assertServerMatchesExpected(t, server, buf, "sample.thing:4.000000|ms|#tagkey:tagvalue")

	dog.SetGaugeWithLabels([]string{"sample", "thing"}, float32(4), []metrics.Label{{"tagkey", "tagvalue"}})
	assertServerMatchesExpected(t, server, buf, "sample.thing:4|g|#tagkey:tagvalue")

	dog.IncrCounterWithLabels([]string{"sample", "thing"}, float32(4), []metrics.Label{{"tagkey", "tagvalue"}})
	assertServerMatchesExpected(t, server, buf, "sample.thing:4|c|#tagkey:tagvalue")

	dog = mockNewDogStatsdSink(DogStatsdAddr, []metrics.Label{{Name: "global"}}, HostnameEnabled) // with hostname, global tags
	dog.IncrCounterWithLabels([]string{"sample", "thing"}, float32(4), []metrics.Label{{"tagkey", "tagvalue"}})
	assertServerMatchesExpected(t, server, buf, "sample.thing:4|c|#global,tagkey:tagvalue,host:test_hostname")
}

func assertServerMatchesExpected(t *testing.T, server *net.UDPConn, buf []byte, expected string) {
	t.Helper()
	n, _ := server.Read(buf)
	msg := buf[:n]
	if string(msg) != expected {
		t.Fatalf("Line %s does not match expected: %s", string(msg), expected)
	}
}
<|endoftext|>


<commit_before>package gorm

import (
	"database/sql"
	"database/sql/driver"
	"fmt"
	"reflect"

	"github.com/lib/pq/hstore"
)

type postgres struct {
}

func (s *postgres) BinVar(i int) string {
	return fmt.Sprintf("$%v", i)
}

func (s *postgres) SupportLastInsertId() bool {
	return false
}

func (d *postgres) SqlTag(value reflect.Value, size int) string {
	switch value.Kind() {
	case reflect.Bool:
		return "boolean"
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr:
		return "integer"
	case reflect.Int64, reflect.Uint64:
		return "bigint"
	case reflect.Float32, reflect.Float64:
		return "numeric"
	case reflect.String:
		if size > 0 && size < 65532 {
			return fmt.Sprintf("varchar(%d)", size)
		}
		return "text"
	case reflect.Struct:
		if value.Type() == timeType {
			return "timestamp with time zone"
		}
	case reflect.Map:
		if value.Type() == hstoreType {
			return "hstore"
		}
	default:
		if _, ok := value.Interface().([]byte); ok {
			return "bytea"
		}
	}
	panic(fmt.Sprintf("invalid sql type %s (%s) for postgres", value.Type().Name(), value.Kind().String()))
}

func (s *postgres) PrimaryKeyTag(value reflect.Value, size int) string {
	switch value.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr:
		return "serial PRIMARY KEY"
	case reflect.Int64, reflect.Uint64:
		return "bigserial PRIMARY KEY"
	default:
		panic("Invalid primary key type")
	}
}

func (s *postgres) ReturningStr(key string) string {
	return fmt.Sprintf("RETURNING \"%v\"", key)
}

func (s *postgres) Quote(key string) string {
	return fmt.Sprintf("\"%s\"", key)
}

func (s *postgres) HasTable(scope *Scope, tableName string) bool {
	var count int
	newScope := scope.New(nil)
	newScope.Raw(fmt.Sprintf("SELECT count(*) FROM INFORMATION_SCHEMA.tables where table_name = %v", newScope.AddToVars(tableName)))
	newScope.DB().QueryRow(newScope.Sql, newScope.SqlVars...).Scan(&count)
	return count > 0
}

func (s *postgres) HasColumn(scope *Scope, tableName string, columnName string) bool {
	var count int
	newScope := scope.New(nil)
	newScope.Raw(fmt.Sprintf("SELECT count(*) FROM information_schema.columns WHERE table_name = %v AND column_name = %v",
		newScope.AddToVars(tableName),
		newScope.AddToVars(columnName),
	))
	newScope.DB().QueryRow(newScope.Sql, newScope.SqlVars...).Scan(&count)
	return count > 0
}

var hstoreType = reflect.TypeOf(Hstore{})

type Hstore map[string]*string

func (h Hstore) Value() (driver.Value, error) {
	hstore := hstore.Hstore{Map: map[string]sql.NullString{}}
	if len(h) == 0 {
		return nil, nil
	}

	for key, value := range h {
		hstore.Map[key] = sql.NullString{*value, true}
	}
	return hstore.Value()
}

func (h *Hstore) Scan(value interface{}) error {
	hstore := hstore.Hstore{}

	if err := hstore.Scan(value); err != nil {
		return err
	}

	if len(hstore.Map) == 0 {
		return nil
	}

	*h = Hstore{}
	for k := range hstore.Map {
		if hstore.Map[k].Valid {
			s := hstore.Map[k].String
			(*h)[k] = &s
		} else {
			(*h)[k] = nil
		}
	}

	return nil
}
<commit_msg>Fix error when deploying to google app engine<commit_after>package gorm

import (
	"database/sql"
	"database/sql/driver"
	"fmt"
	"reflect"

	"github.com/lib/pq/hstore"
)

type postgres struct {
}

func (s *postgres) BinVar(i int) string {
	return fmt.Sprintf("$%v", i)
}

func (s *postgres) SupportLastInsertId() bool {
	return false
}

func (d *postgres) SqlTag(value reflect.Value, size int) string {
	switch value.Kind() {
	case reflect.Bool:
		return "boolean"
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr:
		return "integer"
	case reflect.Int64, reflect.Uint64:
		return "bigint"
	case reflect.Float32, reflect.Float64:
		return "numeric"
	case reflect.String:
		if size > 0 && size < 65532 {
			return fmt.Sprintf("varchar(%d)", size)
		}
		return "text"
	case reflect.Struct:
		if value.Type() == timeType {
			return "timestamp with time zone"
		}
	case reflect.Map:
		if value.Type() == hstoreType {
			return "hstore"
		}
	default:
		if _, ok := value.Interface().([]byte); ok {
			return "bytea"
		}
	}
	panic(fmt.Sprintf("invalid sql type %s (%s) for postgres", value.Type().Name(), value.Kind().String()))
}

func (s *postgres) PrimaryKeyTag(value reflect.Value, size int) string {
	switch value.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr:
		return "serial PRIMARY KEY"
	case reflect.Int64, reflect.Uint64:
		return "bigserial PRIMARY KEY"
	default:
		panic("Invalid primary key type")
	}
}

func (s *postgres) ReturningStr(key string) string {
	return fmt.Sprintf("RETURNING \"%v\"", key)
}

func (s *postgres) Quote(key string) string {
	return fmt.Sprintf("\"%s\"", key)
}

func (s *postgres) HasTable(scope *Scope, tableName string) bool {
	var count int
	newScope := scope.New(nil)
	newScope.Raw(fmt.Sprintf("SELECT count(*) FROM INFORMATION_SCHEMA.tables where table_name = %v", newScope.AddToVars(tableName)))
	newScope.DB().QueryRow(newScope.Sql, newScope.SqlVars...).Scan(&count)
	return count > 0
}

func (s *postgres) HasColumn(scope *Scope, tableName string, columnName string) bool {
	var count int
	newScope := scope.New(nil)
	newScope.Raw(fmt.Sprintf("SELECT count(*) FROM information_schema.columns WHERE table_name = %v AND column_name = %v",
		newScope.AddToVars(tableName),
		newScope.AddToVars(columnName),
	))
	newScope.DB().QueryRow(newScope.Sql, newScope.SqlVars...).Scan(&count)
	return count > 0
}

var hstoreType = reflect.TypeOf(Hstore{})

type Hstore map[string]*string

func (h Hstore) Value() (driver.Value, error) {
	hstore := hstore.Hstore{Map: map[string]sql.NullString{}}
	if len(h) == 0 {
		return nil, nil
	}

	for key, value := range h {
		hstore.Map[key] = sql.NullString{String: *value, Valid: true}
	}
	return hstore.Value()
}

func (h *Hstore) Scan(value interface{}) error {
	hstore := hstore.Hstore{}

	if err := hstore.Scan(value); err != nil {
		return err
	}

	if len(hstore.Map) == 0 {
		return nil
	}

	*h = Hstore{}
	for k := range hstore.Map {
		if hstore.Map[k].Valid {
			s := hstore.Map[k].String
			(*h)[k] = &s
		} else {
			(*h)[k] = nil
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package eventmaster

import (
	"database/sql"
	"encoding/json"
	"fmt"

	_ "github.com/lib/pq"
	"github.com/pkg/errors"
	log "github.com/sirupsen/logrus"
	eventmaster "github.com/wish/eventmaster/proto"
)

// implements datastore
type PostgresStore struct {
	db *sql.DB
}

type PostgresConfig struct {
	Addr        string `json:"addr"`
	Port        int    `json:"port"`
	Database    string `json:"database"`
	ServiceName string `json:"service_name"`
	Username    string `json:"username"`
	Password    string `json:"password"`
}

func NewPostgresStore(c PostgresConfig) (*PostgresStore, error) {
	var host string
	if c.ServiceName != "" {
		host = c.ServiceName + ".service.consul"
	} else {
		host = c.Addr
	}
	log.Infof("Connecting to postgres: %v", host)
	psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
		"password=%s dbname=%s sslmode=disable",
		host, c.Port, c.Username, c.Password, c.Database)
	db, err := sql.Open("postgres", psqlInfo)
	if err != nil {
		return nil, errors.Wrap(err, "Error creating postgres session")
	}
	err = db.Ping()
	if err != nil {
		return nil, errors.Wrap(err, "Error creating postgres session")
	}
	log.Infof("Successfully connected to postgres %s", host)

	return &PostgresStore{
		db: db,
	}, nil
}

func (p *PostgresStore) AddEvent(*Event) error {
	// TODO: implement this function
	return nil
}

func (p *PostgresStore) Find(q *eventmaster.Query, topicIDs []string, dcIDs []string) (Events, error) {
	// TODO: implement this function
	return nil, nil
}

func (p *PostgresStore) FindByID(string, bool) (*Event, error) {
	// TODO: implement this function
	return nil, nil
}

func (p *PostgresStore) FindIDs(*eventmaster.TimeQuery, HandleEvent) error {
	// TODO: implement this function
	return nil
}

func (p *PostgresStore) GetTopics() ([]Topic, error) {
	rows, err := p.db.Query("SELECT topic_id, topic_name, data_schema FROM event_topic")
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var topics []Topic
	var id string
	var name, schema string

	for rows.Next() {
		err = rows.Scan(&id, &name, &schema)
		if err != nil {
			return nil, err
		}
		var s map[string]interface{}
		err := json.Unmarshal([]byte(schema), &s)
		if err != nil {
			return nil, err
		}
		topics = append(topics, Topic{
			ID:     id,
			Name:   name,
			Schema: s,
		})
	}

	return topics, nil
}

func (p *PostgresStore) AddTopic(t RawTopic) error {
	_, err := p.db.Exec("INSERT INTO event_topic (topic_id, topic_name, data_schema) VALUES ($1, $2, $3)", t.ID, t.Name, t.Schema)
	return err
}

func (p *PostgresStore) UpdateTopic(t RawTopic) error {
	_, err := p.db.Exec("UPDATE event_topic SET topic_name=$1, data_schema=$2 WHERE topic_id=$3", t.Name, t.Schema, t.ID)
	return err
}

func (p *PostgresStore) DeleteTopic(id string) error {
	_, err := p.db.Exec("DELETE FROM event_topic WHERE topic_id=$1", id)
	return err
}

func (p *PostgresStore) GetDCs() ([]DC, error) {
	rows, err := p.db.Query("SELECT dc_id, dc from event_dc")
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var dcs []DC

	var dc_id, dc string
	for rows.Next() {
		err = rows.Scan(&dc_id, &dc)
		if err != nil {
			return nil, err
		}
		dcs = append(dcs, DC{
			ID:   dc_id,
			Name: dc,
		})
	}
	return dcs, nil
}

func (p *PostgresStore) AddDC(dc DC) error {
	stmt, err := p.db.Prepare("INSERT INTO event_dc (dc_id, dc) VALUES ($1, $2)")
	if err != nil {
		return errors.Wrap(err, "Failed preparing insert DC statement")
	}
	_, err = stmt.Exec(dc.ID, dc.Name)
	if err != nil {
		return err
	}

	return nil
}

func (p *PostgresStore) UpdateDC(id string, newName string) error {
	_, err := p.db.Exec("UPDATE event_dc SET dc=$1 WHERE dc_id=$2", newName, id)
	return err
}

func (p *PostgresStore) CloseSession() {
	p.db.Close()
}
<commit_msg>Implement AddEvent<commit_after>package eventmaster

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"strings"

	"github.com/lib/pq"
	_ "github.com/lib/pq"
	"github.com/pkg/errors"
	log "github.com/sirupsen/logrus"
	eventmaster "github.com/wish/eventmaster/proto"
)

// implements datastore
type PostgresStore struct {
	db *sql.DB
}

type PostgresConfig struct {
	Addr        string `json:"addr"`
	Port        int    `json:"port"`
	Database    string `json:"database"`
	ServiceName string `json:"service_name"`
	Username    string `json:"username"`
	Password    string `json:"password"`
}

func NewPostgresStore(c PostgresConfig) (*PostgresStore, error) {
	var host string
	if c.ServiceName != "" {
		host = c.ServiceName + ".service.consul"
	} else {
		host = c.Addr
	}
	log.Infof("Connecting to postgres: %v", host)
	psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
		"password=%s dbname=%s sslmode=disable",
		host, c.Port, c.Username, c.Password, c.Database)
	db, err := sql.Open("postgres", psqlInfo)
	if err != nil {
		return nil, errors.Wrap(err, "Error creating postgres session")
	}
	err = db.Ping()
	if err != nil {
		return nil, errors.Wrap(err, "Error creating postgres session")
	}
	log.Infof("Successfully connected to postgres %s", host)

	return &PostgresStore{
		db: db,
	}, nil
}

func (p *PostgresStore) AddEvent(e *Event) error {
	data := "{}"
	if e.Data != nil {
		dataBytes, err := json.Marshal(e.Data)
		if err != nil {
			return err
		}
		data = string(dataBytes)
	}

	tx, err := p.db.Begin()
	if err != nil {
		return err
	}

	_, err = tx.Exec("INSERT INTO event "+
		"(event_id, parent_event_id, dc_id, topic_id, host, target_host_set, \"user\", event_time, tag_set, received_time)"+
		" VALUES ($1, $2, $3, $4, $5, $6, $7, to_timestamp($8), $9, to_timestamp($10))",
		e.EventID, e.ParentEventID, e.DCID, e.TopicID, strings.ToLower(e.Host), pq.Array(e.TargetHosts), strings.ToLower(e.User), e.EventTime/1000, pq.Array(e.Tags), e.ReceivedTime/1000)

	if err != nil {
		tx.Rollback()
		return err
	}

	_, err = tx.Exec("INSERT INTO event_metadata (event_id, data_json) VALUES ($1, $2)", e.EventID, data)
	if err != nil {
		tx.Rollback()
		return err
	}

	return tx.Commit()
}

func (p *PostgresStore) Find(q *eventmaster.Query, topicIDs []string, dcIDs []string) (Events, error) {
	// TODO: implement this function
	return nil, nil
}

func (p *PostgresStore) FindByID(string, bool) (*Event, error) {
	// TODO: implement this function
	return nil, nil
}

func (p *PostgresStore) FindIDs(*eventmaster.TimeQuery, HandleEvent) error {
	// TODO: implement this function
	return nil
}

func (p *PostgresStore) GetTopics() ([]Topic, error) {
	rows, err := p.db.Query("SELECT topic_id, topic_name, data_schema FROM event_topic")
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var topics []Topic
	var id string
	var name, schema string

	for rows.Next() {
		err = rows.Scan(&id, &name, &schema)
		if err != nil {
			return nil, err
		}
		var s map[string]interface{}
		err := json.Unmarshal([]byte(schema), &s)
		if err != nil {
			return nil, err
		}
		topics = append(topics, Topic{
			ID:     id,
			Name:   name,
			Schema: s,
		})
	}

	return topics, nil
}

func (p *PostgresStore) AddTopic(t RawTopic) error {
	_, err := p.db.Exec("INSERT INTO event_topic (topic_id, topic_name, data_schema) VALUES ($1, $2, $3)", t.ID, t.Name, t.Schema)
	return err
}

func (p *PostgresStore) UpdateTopic(t RawTopic) error {
	_, err := p.db.Exec("UPDATE event_topic SET topic_name=$1, data_schema=$2 WHERE topic_id=$3", t.Name, t.Schema, t.ID)
	return err
}

func (p *PostgresStore) DeleteTopic(id string) error {
	_, err := p.db.Exec("DELETE FROM event_topic WHERE topic_id=$1", id)
	return err
}

func (p *PostgresStore) GetDCs() ([]DC, error) {
	rows, err := p.db.Query("SELECT dc_id, dc from event_dc")
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var dcs []DC

	var dc_id, dc string
	for rows.Next() {
		err = rows.Scan(&dc_id, &dc)
		if err != nil {
			return nil, err
		}
		dcs = append(dcs, DC{
			ID:   dc_id,
			Name: dc,
		})
	}
	return dcs, nil
}

func (p *PostgresStore) AddDC(dc DC) error {
	stmt, err := p.db.Prepare("INSERT INTO event_dc (dc_id, dc) VALUES ($1, $2)")
	if err != nil {
		return errors.Wrap(err, "Failed preparing insert DC statement")
	}
	_, err = stmt.Exec(dc.ID, dc.Name)
	if err != nil {
		return err
	}

	return nil
}

func (p *PostgresStore) UpdateDC(id string, newName string) error {
	_, err := p.db.Exec("UPDATE event_dc SET dc=$1 WHERE dc_id=$2", newName, id)
	return err
}

func (p *PostgresStore) CloseSession() {
	p.db.Close()
}
<|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 create

import (
	"testing"

	rbac "k8s.io/api/rbac/v1"
	apiequality "k8s.io/apimachinery/pkg/api/equality"
	"k8s.io/apimachinery/pkg/apis/meta/v1"
)

func TestCreateRoleBinding(t *testing.T) {
	tests := []struct {
		options  *RoleBindingOptions
		expected *rbac.RoleBinding
	}{
		{
			options: &RoleBindingOptions{
				Role:            "fake-role",
				Users:           []string{"fake-user"},
				Groups:          []string{"fake-group"},
				ServiceAccounts: []string{"fake-namespace:fake-account"},
				Name:            "fake-binding",
			},
			expected: &rbac.RoleBinding{
				TypeMeta: v1.TypeMeta{
					Kind:       "RoleBinding",
					APIVersion: "rbac.authorization.k8s.io/v1",
				},
				ObjectMeta: v1.ObjectMeta{
					Name: "fake-binding",
				},
				RoleRef: rbac.RoleRef{
					APIGroup: rbac.GroupName,
					Kind:     "Role",
					Name:     "fake-role",
				},
				Subjects: []rbac.Subject{
					{
						Kind:     rbac.UserKind,
						APIGroup: "rbac.authorization.k8s.io",
						Name:     "fake-user",
					},
					{
						Kind:     rbac.GroupKind,
						APIGroup: "rbac.authorization.k8s.io",
						Name:     "fake-group",
					},
					{
						Kind:      rbac.ServiceAccountKind,
						Namespace: "fake-namespace",
						Name:      "fake-account",
					},
				},
			},
		},
	}

	for i, tc := range tests {
		t.Run(string(i), func(t *testing.T) {
			roleBinding, err := tc.options.createRoleBinding()
			if err != nil {
				t.Errorf("unexpected error:\n%#v\n", err)
				return
			}
			if !apiequality.Semantic.DeepEqual(roleBinding, tc.expected) {
				t.Errorf("expected:\n%#v\ngot:\n%#v", tc.expected, roleBinding)
			}
		})
	}

}
<commit_msg>replace string casting with fmt.sprintf in test<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 create

import (
	"fmt"
	"testing"

	rbac "k8s.io/api/rbac/v1"
	apiequality "k8s.io/apimachinery/pkg/api/equality"
	"k8s.io/apimachinery/pkg/apis/meta/v1"
)

func TestCreateRoleBinding(t *testing.T) {
	tests := []struct {
		options  *RoleBindingOptions
		expected *rbac.RoleBinding
	}{
		{
			options: &RoleBindingOptions{
				Role:            "fake-role",
				Users:           []string{"fake-user"},
				Groups:          []string{"fake-group"},
				ServiceAccounts: []string{"fake-namespace:fake-account"},
				Name:            "fake-binding",
			},
			expected: &rbac.RoleBinding{
				TypeMeta: v1.TypeMeta{
					Kind:       "RoleBinding",
					APIVersion: "rbac.authorization.k8s.io/v1",
				},
				ObjectMeta: v1.ObjectMeta{
					Name: "fake-binding",
				},
				RoleRef: rbac.RoleRef{
					APIGroup: rbac.GroupName,
					Kind:     "Role",
					Name:     "fake-role",
				},
				Subjects: []rbac.Subject{
					{
						Kind:     rbac.UserKind,
						APIGroup: "rbac.authorization.k8s.io",
						Name:     "fake-user",
					},
					{
						Kind:     rbac.GroupKind,
						APIGroup: "rbac.authorization.k8s.io",
						Name:     "fake-group",
					},
					{
						Kind:      rbac.ServiceAccountKind,
						Namespace: "fake-namespace",
						Name:      "fake-account",
					},
				},
			},
		},
	}

	for i, tc := range tests {
		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
			roleBinding, err := tc.options.createRoleBinding()
			if err != nil {
				t.Errorf("unexpected error:\n%#v\n", err)
				return
			}
			if !apiequality.Semantic.DeepEqual(roleBinding, tc.expected) {
				t.Errorf("expected:\n%#v\ngot:\n%#v", tc.expected, roleBinding)
			}
		})
	}

}
<|endoftext|>


<commit_before>package admin

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/golang/glog"
	"github.com/spf13/cobra"

	kapi "k8s.io/kubernetes/pkg/api"
	kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
	"k8s.io/kubernetes/pkg/util/cert"

	cliconfig "github.com/openshift/origin/pkg/cmd/cli/config"
	"github.com/openshift/origin/pkg/cmd/server/crypto"
	"github.com/openshift/origin/pkg/cmd/templates"
	"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
	clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
)

const CreateKubeConfigCommandName = "create-kubeconfig"

var createKubeConfigLongDesc = templates.LongDesc(`
  Create's a .kubeconfig file at <--kubeconfig> that looks like this:

      clusters:
      - cluster:
      certificate-authority-data: <contents of --certificate-authority>
      server: <--master>
      name: <--cluster>
      - cluster:
      certificate-authority-data: <contents of --certificate-authority>
      server: <--public-master>
      name: public-<--cluster>
      contexts:
      - context:
      cluster: <--cluster>
      user: <--user>
      namespace: <--namespace>
      name: <--context>
      - context:
      cluster: public-<--cluster>
      user: <--user>
      namespace: <--namespace>
      name: public-<--context>
      current-context: <--context>
      kind: Config
      users:
      - name: <--user>
      user:
      client-certificate-data: <contents of --client-certificate>
      client-key-data: <contents of --client-key>`)

type CreateKubeConfigOptions struct {
	APIServerURL       string
	PublicAPIServerURL string
	APIServerCAFiles   []string

	CertFile string
	KeyFile  string

	ContextNamespace string

	KubeConfigFile string
	Output         io.Writer
}

func NewCommandCreateKubeConfig(commandName string, fullName string, out io.Writer) *cobra.Command {
	options := &CreateKubeConfigOptions{Output: out}

	cmd := &cobra.Command{
		Use:   commandName,
		Short: "Create a basic .kubeconfig file from client certs",
		Long:  createKubeConfigLongDesc,
		Run: func(cmd *cobra.Command, args []string) {
			if err := options.Validate(args); err != nil {
				kcmdutil.CheckErr(kcmdutil.UsageError(cmd, err.Error()))
			}

			if _, err := options.CreateKubeConfig(); err != nil {
				kcmdutil.CheckErr(err)
			}
		},
	}

	flags := cmd.Flags()

	flags.StringVar(&options.APIServerURL, "master", "https://localhost:8443", "The API server's URL.")
	flags.StringVar(&options.PublicAPIServerURL, "public-master", "", "The API public facing server's URL (if applicable).")
	flags.StringSliceVar(&options.APIServerCAFiles, "certificate-authority", []string{"openshift.local.config/master/ca.crt"}, "Files containing signing authorities to use to verify the API server's serving certificate.")
	flags.StringVar(&options.CertFile, "client-certificate", "", "The client cert file.")
	flags.StringVar(&options.KeyFile, "client-key", "", "The client key file.")
	flags.StringVar(&options.ContextNamespace, "namespace", kapi.NamespaceDefault, "Namespace for this context in .kubeconfig.")
	flags.StringVar(&options.KubeConfigFile, "kubeconfig", ".kubeconfig", "Path for the resulting .kubeconfig file.")

	// autocompletion hints
	cmd.MarkFlagFilename("certificate-authority")
	cmd.MarkFlagFilename("client-certificate")
	cmd.MarkFlagFilename("client-key")
	cmd.MarkFlagFilename("kubeconfig")

	return cmd
}

func (o CreateKubeConfigOptions) Validate(args []string) error {
	if len(args) != 0 {
		return errors.New("no arguments are supported")
	}
	if len(o.KubeConfigFile) == 0 {
		return errors.New("kubeconfig must be provided")
	}
	if len(o.CertFile) == 0 {
		return errors.New("client-certificate must be provided")
	}
	if len(o.KeyFile) == 0 {
		return errors.New("client-key must be provided")
	}
	if len(o.APIServerCAFiles) == 0 {
		return errors.New("certificate-authority must be provided")
	} else {
		for _, caFile := range o.APIServerCAFiles {
			if _, err := cert.NewPool(caFile); err != nil {
				return fmt.Errorf("certificate-authority must be a valid certificate file: %v", err)
			}
		}
	}
	if len(o.ContextNamespace) == 0 {
		return errors.New("namespace must be provided")
	}
	if len(o.APIServerURL) == 0 {
		return errors.New("master must be provided")
	}

	return nil
}

func (o CreateKubeConfigOptions) CreateKubeConfig() (*clientcmdapi.Config, error) {
	glog.V(4).Infof("creating a .kubeconfig with: %#v", o)

	// read all the referenced filenames
	caData, err := readFiles(o.APIServerCAFiles, []byte("\n"))
	if err != nil {
		return nil, err
	}
	certData, err := ioutil.ReadFile(o.CertFile)
	if err != nil {
		return nil, err
	}
	keyData, err := ioutil.ReadFile(o.KeyFile)
	if err != nil {
		return nil, err
	}
	certConfig, err := crypto.GetTLSCertificateConfig(o.CertFile, o.KeyFile)
	if err != nil {
		return nil, err
	}

	// determine all the nicknames
	clusterNick, err := cliconfig.GetClusterNicknameFromURL(o.APIServerURL)
	if err != nil {
		return nil, err
	}
	userNick, err := cliconfig.GetUserNicknameFromCert(clusterNick, certConfig.Certs...)
	if err != nil {
		return nil, err
	}
	contextNick := cliconfig.GetContextNickname(o.ContextNamespace, clusterNick, userNick)

	credentials := make(map[string]*clientcmdapi.AuthInfo)
	credentials[userNick] = &clientcmdapi.AuthInfo{
		ClientCertificateData: certData,
		ClientKeyData:         keyData,
	}

	clusters := make(map[string]*clientcmdapi.Cluster)
	clusters[clusterNick] = &clientcmdapi.Cluster{
		Server: o.APIServerURL,
		CertificateAuthorityData: caData,
	}

	contexts := make(map[string]*clientcmdapi.Context)
	contexts[contextNick] = &clientcmdapi.Context{Cluster: clusterNick, AuthInfo: userNick, Namespace: o.ContextNamespace}

	createPublic := (len(o.PublicAPIServerURL) > 0) && o.APIServerURL != o.PublicAPIServerURL
	if createPublic {
		publicClusterNick, err := cliconfig.GetClusterNicknameFromURL(o.PublicAPIServerURL)
		if err != nil {
			return nil, err
		}
		publicContextNick := cliconfig.GetContextNickname(o.ContextNamespace, publicClusterNick, userNick)

		clusters[publicClusterNick] = &clientcmdapi.Cluster{
			Server: o.PublicAPIServerURL,
			CertificateAuthorityData: caData,
		}
		contexts[publicContextNick] = &clientcmdapi.Context{Cluster: publicClusterNick, AuthInfo: userNick, Namespace: o.ContextNamespace}
	}

	kubeConfig := &clientcmdapi.Config{
		Clusters:       clusters,
		AuthInfos:      credentials,
		Contexts:       contexts,
		CurrentContext: contextNick,
	}

	glog.V(3).Infof("Generating '%s' API client config as %s\n", userNick, o.KubeConfigFile)
	// Ensure the parent dir exists
	if err := os.MkdirAll(filepath.Dir(o.KubeConfigFile), os.FileMode(0755)); err != nil {
		return nil, err
	}
	if err := clientcmd.WriteToFile(*kubeConfig, o.KubeConfigFile); err != nil {
		return nil, err
	}

	return kubeConfig, nil
}
<commit_msg>normalize server url before writing to config<commit_after>package admin

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/golang/glog"
	"github.com/spf13/cobra"

	kapi "k8s.io/kubernetes/pkg/api"
	kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
	"k8s.io/kubernetes/pkg/util/cert"

	"github.com/openshift/origin/pkg/cmd/cli/config"
	cliconfig "github.com/openshift/origin/pkg/cmd/cli/config"
	"github.com/openshift/origin/pkg/cmd/server/crypto"
	"github.com/openshift/origin/pkg/cmd/templates"
	"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
	clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
)

const CreateKubeConfigCommandName = "create-kubeconfig"

var createKubeConfigLongDesc = templates.LongDesc(`
  Create's a .kubeconfig file at <--kubeconfig> that looks like this:

      clusters:
      - cluster:
      certificate-authority-data: <contents of --certificate-authority>
      server: <--master>
      name: <--cluster>
      - cluster:
      certificate-authority-data: <contents of --certificate-authority>
      server: <--public-master>
      name: public-<--cluster>
      contexts:
      - context:
      cluster: <--cluster>
      user: <--user>
      namespace: <--namespace>
      name: <--context>
      - context:
      cluster: public-<--cluster>
      user: <--user>
      namespace: <--namespace>
      name: public-<--context>
      current-context: <--context>
      kind: Config
      users:
      - name: <--user>
      user:
      client-certificate-data: <contents of --client-certificate>
      client-key-data: <contents of --client-key>`)

type CreateKubeConfigOptions struct {
	APIServerURL       string
	PublicAPIServerURL string
	APIServerCAFiles   []string

	CertFile string
	KeyFile  string

	ContextNamespace string

	KubeConfigFile string
	Output         io.Writer
}

func NewCommandCreateKubeConfig(commandName string, fullName string, out io.Writer) *cobra.Command {
	options := &CreateKubeConfigOptions{Output: out}

	cmd := &cobra.Command{
		Use:   commandName,
		Short: "Create a basic .kubeconfig file from client certs",
		Long:  createKubeConfigLongDesc,
		Run: func(cmd *cobra.Command, args []string) {
			if err := options.Validate(args); err != nil {
				kcmdutil.CheckErr(kcmdutil.UsageError(cmd, err.Error()))
			}

			if _, err := options.CreateKubeConfig(); err != nil {
				kcmdutil.CheckErr(err)
			}
		},
	}

	flags := cmd.Flags()

	flags.StringVar(&options.APIServerURL, "master", "https://localhost:8443", "The API server's URL.")
	flags.StringVar(&options.PublicAPIServerURL, "public-master", "", "The API public facing server's URL (if applicable).")
	flags.StringSliceVar(&options.APIServerCAFiles, "certificate-authority", []string{"openshift.local.config/master/ca.crt"}, "Files containing signing authorities to use to verify the API server's serving certificate.")
	flags.StringVar(&options.CertFile, "client-certificate", "", "The client cert file.")
	flags.StringVar(&options.KeyFile, "client-key", "", "The client key file.")
	flags.StringVar(&options.ContextNamespace, "namespace", kapi.NamespaceDefault, "Namespace for this context in .kubeconfig.")
	flags.StringVar(&options.KubeConfigFile, "kubeconfig", ".kubeconfig", "Path for the resulting .kubeconfig file.")

	// autocompletion hints
	cmd.MarkFlagFilename("certificate-authority")
	cmd.MarkFlagFilename("client-certificate")
	cmd.MarkFlagFilename("client-key")
	cmd.MarkFlagFilename("kubeconfig")

	return cmd
}

func (o CreateKubeConfigOptions) Validate(args []string) error {
	if len(args) != 0 {
		return errors.New("no arguments are supported")
	}
	if len(o.KubeConfigFile) == 0 {
		return errors.New("kubeconfig must be provided")
	}
	if len(o.CertFile) == 0 {
		return errors.New("client-certificate must be provided")
	}
	if len(o.KeyFile) == 0 {
		return errors.New("client-key must be provided")
	}
	if len(o.APIServerCAFiles) == 0 {
		return errors.New("certificate-authority must be provided")
	} else {
		for _, caFile := range o.APIServerCAFiles {
			if _, err := cert.NewPool(caFile); err != nil {
				return fmt.Errorf("certificate-authority must be a valid certificate file: %v", err)
			}
		}
	}
	if len(o.ContextNamespace) == 0 {
		return errors.New("namespace must be provided")
	}
	if len(o.APIServerURL) == 0 {
		return errors.New("master must be provided")
	}

	return nil
}

func (o CreateKubeConfigOptions) CreateKubeConfig() (*clientcmdapi.Config, error) {
	glog.V(4).Infof("creating a .kubeconfig with: %#v", o)

	// read all the referenced filenames
	caData, err := readFiles(o.APIServerCAFiles, []byte("\n"))
	if err != nil {
		return nil, err
	}
	certData, err := ioutil.ReadFile(o.CertFile)
	if err != nil {
		return nil, err
	}
	keyData, err := ioutil.ReadFile(o.KeyFile)
	if err != nil {
		return nil, err
	}
	certConfig, err := crypto.GetTLSCertificateConfig(o.CertFile, o.KeyFile)
	if err != nil {
		return nil, err
	}

	// determine all the nicknames
	clusterNick, err := cliconfig.GetClusterNicknameFromURL(o.APIServerURL)
	if err != nil {
		return nil, err
	}
	userNick, err := cliconfig.GetUserNicknameFromCert(clusterNick, certConfig.Certs...)
	if err != nil {
		return nil, err
	}
	contextNick := cliconfig.GetContextNickname(o.ContextNamespace, clusterNick, userNick)

	credentials := make(map[string]*clientcmdapi.AuthInfo)
	credentials[userNick] = &clientcmdapi.AuthInfo{
		ClientCertificateData: certData,
		ClientKeyData:         keyData,
	}

	// normalize the provided server to a format expected by config
	o.APIServerURL, err = config.NormalizeServerURL(o.APIServerURL)
	if err != nil {
		return nil, err
	}

	clusters := make(map[string]*clientcmdapi.Cluster)
	clusters[clusterNick] = &clientcmdapi.Cluster{
		Server: o.APIServerURL,
		CertificateAuthorityData: caData,
	}

	contexts := make(map[string]*clientcmdapi.Context)
	contexts[contextNick] = &clientcmdapi.Context{Cluster: clusterNick, AuthInfo: userNick, Namespace: o.ContextNamespace}

	createPublic := (len(o.PublicAPIServerURL) > 0) && o.APIServerURL != o.PublicAPIServerURL
	if createPublic {
		publicClusterNick, err := cliconfig.GetClusterNicknameFromURL(o.PublicAPIServerURL)
		if err != nil {
			return nil, err
		}
		publicContextNick := cliconfig.GetContextNickname(o.ContextNamespace, publicClusterNick, userNick)

		clusters[publicClusterNick] = &clientcmdapi.Cluster{
			Server: o.PublicAPIServerURL,
			CertificateAuthorityData: caData,
		}
		contexts[publicContextNick] = &clientcmdapi.Context{Cluster: publicClusterNick, AuthInfo: userNick, Namespace: o.ContextNamespace}
	}

	kubeConfig := &clientcmdapi.Config{
		Clusters:       clusters,
		AuthInfos:      credentials,
		Contexts:       contexts,
		CurrentContext: contextNick,
	}

	glog.V(3).Infof("Generating '%s' API client config as %s\n", userNick, o.KubeConfigFile)
	// Ensure the parent dir exists
	if err := os.MkdirAll(filepath.Dir(o.KubeConfigFile), os.FileMode(0755)); err != nil {
		return nil, err
	}
	if err := clientcmd.WriteToFile(*kubeConfig, o.KubeConfigFile); err != nil {
		return nil, err
	}

	return kubeConfig, nil
}
<|endoftext|>


<commit_before>package peer

import (
	"net"
	"sync"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/google/uuid"
	"github.com/ubclaunchpad/cumulus/conn"
	"github.com/ubclaunchpad/cumulus/msg"
)

const (
	// DefaultPort is the TCP port hosts will communicate over if none is
	// provided
	DefaultPort = 8000
	// DefaultIP is the IP address new hosts will use if none if provided
	DefaultIP = "127.0.0.1"
	// Timeout is the time after which reads from a stream will timeout
	Timeout = time.Second * 30
)

// PStore stores information about every peer we are connected to. All peers we
// connect to should have a reference to this peerstore so they can populate it.
var PStore = &PeerStore{peers: make(map[string]*Peer, 0)}

// PeerStore is a thread-safe container for all the peers we are currently
// connected to.
type PeerStore struct {
	peers map[string]*Peer
	lock  sync.RWMutex
}

// NewPeerStore returns an initialized peerstore.
func NewPeerStore() *PeerStore {
	return &PeerStore{
		peers: make(map[string]*Peer, 0),
		lock:  sync.RWMutex{},
	}
}

// Add synchronously adds the given peer to the peerstore
func (ps *PeerStore) Add(p *Peer) {
	ps.lock.Lock()
	defer ps.lock.Unlock()
	ps.peers[p.ID.String()] = p
}

// Remove synchronously removes the given peer from the peerstore
func (ps *PeerStore) Remove(id string) {
	ps.lock.Lock()
	defer ps.lock.Unlock()
	delete(ps.peers, id)
}

// Get synchronously retreives the peer with the given id from the peerstore
func (ps *PeerStore) Get(id string) *Peer {
	ps.lock.RLock()
	defer ps.lock.RUnlock()
	return ps.peers[id]
}

// Addrs returns the list of addresses of the peers in the peerstore in the form
// <IP addr>:<port>
func (ps *PeerStore) Addrs() []string {
	ps.lock.RLock()
	defer ps.lock.RUnlock()
	addrs := make([]string, len(ps.peers), len(ps.peers))
	for _, p := range ps.peers {
		addrs = append(addrs, p.Connection.RemoteAddr().String())
	}
	return addrs
}

// ChanStore is a threadsafe container for response channels.
type ChanStore struct {
	chans map[string]chan *msg.Response
	lock  sync.RWMutex
}

// Add synchronously adds a channel with the given id to the store.
func (cs *ChanStore) Add(id string, channel chan *msg.Response) {
	cs.lock.Lock()
	defer cs.lock.Lock()
	cs.chans[id] = channel
}

// Remove synchronously removes the channel with the given ID.
func (cs *ChanStore) Remove(id string) {
	cs.lock.Lock()
	defer cs.lock.Unlock()
	delete(cs.chans, id)
}

// Get retrieves the channel with the given ID.
func (cs *ChanStore) Get(id string) chan *msg.Response {
	cs.lock.RLock()
	defer cs.lock.RUnlock()
	return cs.chans[id]
}

// Peer represents a remote peer we are connected to.
type Peer struct {
	ID         uuid.UUID
	Connection net.Conn
	Store      *PeerStore
	resChans   *ChanStore
	reqChan    chan *msg.Request
	pushChan   chan *msg.Push
	lock       sync.RWMutex
}

// New returns a new Peer
func New(c net.Conn, ps *PeerStore) *Peer {
	cs := &ChanStore{
		chans: make(map[string]chan *msg.Response),
		lock:  sync.RWMutex{},
	}
	return &Peer{
		ID:         uuid.New(),
		Connection: c,
		Store:      ps,
		resChans:   cs,
		reqChan:    make(chan *msg.Request),
		pushChan:   make(chan *msg.Push),
	}
}

// ConnectionHandler is called when a new connection is opened with us by a
// remote peer. It will create a dispatcher and message handlers to handle
// sending and retrieving messages over the new connection.
func ConnectionHandler(c net.Conn) {
	p := New(c, PStore)
	PStore.Add(p)

	go p.Dispatch()
	go p.PushHandler()
	go p.RequestHandler()

	log.Infof("Connected to %s", p.Connection.RemoteAddr().String())
}

// Dispatch listens on this peer's Connection and passes received messages
// to the appropriate message handlers.
func (p *Peer) Dispatch() {
	p.Connection.SetDeadline(time.Now().Add(Timeout))

	for {
		message, err := msg.Read(p.Connection)
		if err != nil {
			log.WithError(err).Error("Dispatcher failed to read message")
			continue
		}

		switch message.(type) {
		case *msg.Request:
			p.reqChan <- message.(*msg.Request)
			break
		case *msg.Response:
			res := message.(*msg.Response)
			resChan := p.resChans.Get(res.ID)
			if resChan != nil {
				resChan <- message.(*msg.Response)
			} else {
				log.Errorf("Dispatcher could not find channel for response %s", res.ID)
			}
			p.resChans.Remove(res.ID)
			break
		case *msg.Push:
			p.pushChan <- message.(*msg.Push)
			break
		default:
			// Invalid messgae type. Ignore
			log.Debug("Dispatcher received message with invalid type")
		}
	}
}

// RequestHandler waits on this peer's request channel for incoming requests
// from the Dispatcher, responding to each request appropriately.
func (p *Peer) RequestHandler() {
	var req *msg.Request
	for {
		select {
		case req = <-p.reqChan:
			break
		case <-time.After(Timeout):
			continue
		}

		res := msg.Response{ID: req.ID}

		switch req.ResourceType {
		case msg.ResourcePeerInfo:
			res.Resource = p.Store.Addrs()
			break
		case msg.ResourceBlock, msg.ResourceTransaction:
			res.Error = msg.NewProtocolError(msg.NotImplemented,
				"Block and Transaction requests are not yet implemented on this peer")
			break
		default:
			res.Error = msg.NewProtocolError(msg.InvalidResourceType,
				"Invalid resource type")
		}

		err := res.Write(p.Connection)
		if err != nil {
			log.WithError(err).Error("RequestHandler failed to send response")
		}
	}
}

// PushHandler waits on this peer's request channel for incoming requests
// from the Dispatcher, responding to each request appropriately.
func (p *Peer) PushHandler() {
	var push *msg.Push
	for {
		select {
		case push = <-p.pushChan:
			break
		case <-time.After(Timeout):
			continue
		}

		switch push.ResourceType {
		case msg.ResourcePeerInfo:
			for _, addr := range push.Resource.([]string) {
				c, err := conn.Dial(addr)
				if err != nil {
					log.WithError(err).Errorf("PushHandler fialed to dial peer %s", addr)
				} else {
					ConnectionHandler(c)
				}
			}
			break
		case msg.ResourceBlock:
		case msg.ResourceTransaction:
		default:
			// Invalid resource type. Ignore
		}
	}
}

// AwaitResponse waits on a response channel for a response message sent by the
// Dispatcher. When a response arrives it is handled appropriately.
func (p *Peer) AwaitResponse(req msg.Request, c chan *msg.Response) {
	defer p.resChans.Remove(req.ID)
	select {
	case res := <-c:
		// TODO: do something with the response
		log.Debugf("Received response %s", res.ID)
	case <-time.After(Timeout):
		break
	}
}

// Request sends the given request over this peer's Connection and spawns a
// response listener with AwaitResponse. Returns error if request could not be
// written.
func (p *Peer) Request(req msg.Request) error {
	resChan := make(chan *msg.Response)
	p.resChans.Add(req.ID, resChan)
	err := req.Write(p.Connection)
	if err != nil {
		p.resChans.Remove(req.ID)
		return err
	}

	go p.AwaitResponse(req, resChan)
	return nil
}
<commit_msg>Add EOF handling logic for reading from connection<commit_after>package peer

import (
	"io"
	"net"
	"sync"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/google/uuid"
	"github.com/ubclaunchpad/cumulus/msg"
)

const (
	// DefaultPort is the TCP port hosts will communicate over if none is
	// provided
	DefaultPort = 8000
	// DefaultIP is the IP address new hosts will use if none if provided
	DefaultIP = "127.0.0.1"
	// Timeout is the time after which reads from a stream will timeout
	Timeout = time.Second * 30
	// messageWaitTime is the amount of time the dispatcher should wait before
	// attempting to read from the connection again when no data was received
	messageWaitTime = time.Second * 5
)

// PStore stores information about every peer we are connected to. All peers we
// connect to should have a reference to this peerstore so they can populate it.
var PStore = &PeerStore{peers: make(map[string]*Peer, 0)}

// PeerStore is a thread-safe container for all the peers we are currently
// connected to.
type PeerStore struct {
	peers map[string]*Peer
	lock  sync.RWMutex
}

// NewPeerStore returns an initialized peerstore.
func NewPeerStore() *PeerStore {
	return &PeerStore{
		peers: make(map[string]*Peer, 0),
		lock:  sync.RWMutex{},
	}
}

// Add synchronously adds the given peer to the peerstore
func (ps *PeerStore) Add(p *Peer) {
	ps.lock.Lock()
	defer ps.lock.Unlock()
	ps.peers[p.ID.String()] = p
}

// Remove synchronously removes the given peer from the peerstore
func (ps *PeerStore) Remove(id string) {
	ps.lock.Lock()
	defer ps.lock.Unlock()
	delete(ps.peers, id)
}

// Get synchronously retreives the peer with the given id from the peerstore
func (ps *PeerStore) Get(id string) *Peer {
	ps.lock.RLock()
	defer ps.lock.RUnlock()
	return ps.peers[id]
}

// Addrs returns the list of addresses of the peers in the peerstore in the form
// <IP addr>:<port>
func (ps *PeerStore) Addrs() []string {
	ps.lock.RLock()
	defer ps.lock.RUnlock()
	addrs := make([]string, len(ps.peers), len(ps.peers))
	for _, p := range ps.peers {
		addrs = append(addrs, p.Connection.RemoteAddr().String())
	}
	return addrs
}

// Peer represents a remote peer we are connected to.
type Peer struct {
	ID               uuid.UUID
	Connection       net.Conn
	Store            *PeerStore
	responseHandlers map[string]ResponseHandler
	reqChan          chan *msg.Request
	pushChan         chan *msg.Push
	killChan         chan bool
	lock             sync.RWMutex
}

// ResponseHandler is any function that handles a response to a request.
type ResponseHandler func(*msg.Response)

// New returns a new Peer
func New(c net.Conn, ps *PeerStore) *Peer {
	return &Peer{
		ID:               uuid.New(),
		Connection:       c,
		Store:            ps,
		responseHandlers: make(map[string]ResponseHandler),
		reqChan:          make(chan *msg.Request),
		pushChan:         make(chan *msg.Push),
		killChan:         make(chan bool),
	}
}

// ConnectionHandler is called when a new connection is opened with us by a
// remote peer. It will create a dispatcher and message handlers to handle
// sending and retrieving messages over the new connection.
func ConnectionHandler(c net.Conn) {
	p := New(c, PStore)
	PStore.Add(p)

	go p.Dispatch()
	go p.PushHandler()
	go p.RequestHandler()

	log.Infof("Connected to %s", p.Connection.RemoteAddr().String())
}

// Dispatch listens on this peer's Connection and passes received messages
// to the appropriate message handlers.
func (p *Peer) Dispatch() {
	// After 3 consecutive errors we kill this connection and its associated
	// handlers using the killChan
	errCount := 0

	for {
		message, err := msg.Read(p.Connection)
		if err != nil {
			if err == io.EOF {
				// This just means the peer hasn't sent anything
				select {
				case <-time.After(messageWaitTime):
				}
			} else {
				log.WithError(err).Error("Dispatcher failed to read message")
				if errCount == 3 {
					p.killChan <- true
					p.Connection.Close()
					return
				}
				errCount++
			}
			continue
		}
		errCount = 0

		switch message.(type) {
		case *msg.Request:
			p.reqChan <- message.(*msg.Request)
		case *msg.Response:
			res := message.(*msg.Response)
			rh := p.getResponseHandler(res.ID)
			if rh == nil {
				log.Error("Dispatcher could not find response handler for response")
			}
			go rh(res)
			p.removeResponseHandler(res.ID)
		case *msg.Push:
			p.pushChan <- message.(*msg.Push)
		default:
			// Invalid messgae type. Ignore
			log.Debug("Dispatcher received message with invalid type")
		}
	}
}

// RequestHandler waits on this peer's request channel for incoming requests
// from the Dispatcher, responding to each request appropriately.
func (p *Peer) RequestHandler() {
	var req *msg.Request
	for {
		select {
		case req = <-p.reqChan:
		case <-p.killChan:
			return
		}

		res := msg.Response{ID: req.ID}

		switch req.ResourceType {
		case msg.ResourcePeerInfo:
			res.Resource = p.Store.Addrs()
		case msg.ResourceBlock, msg.ResourceTransaction:
			res.Error = msg.NewProtocolError(msg.NotImplemented,
				"Block and Transaction requests are not yet implemented on this peer")
		default:
			res.Error = msg.NewProtocolError(msg.InvalidResourceType,
				"Invalid resource type")
		}

		err := res.Write(p.Connection)
		if err != nil {
			log.WithError(err).Error("RequestHandler failed to send response")
		}
	}
}

// PushHandler waits on this peer's request channel for incoming requests
// from the Dispatcher, responding to each request appropriately.
func (p *Peer) PushHandler() {
	var push *msg.Push
	for {
		select {
		case push = <-p.pushChan:
		case <-p.killChan:
			return
		}

		switch push.ResourceType {
		case msg.ResourceBlock:
		case msg.ResourceTransaction:
		default:
			// Invalid resource type. Ignore
		}
	}
}

// Request sends the given request over this peer's Connection and registers the
// given response hadnler to be called when the response arrives at the dispatcher.
// Returns error if request could not be written.
func (p *Peer) Request(req msg.Request, rh ResponseHandler) error {
	p.addResponseHandler(req.ID, rh)
	err := req.Write(p.Connection)
	if err != nil {
		return err
	}
	return nil
}

func (p *Peer) addResponseHandler(id string, rh ResponseHandler) {
	p.lock.Lock()
	defer p.lock.Unlock()
	p.responseHandlers[id] = rh
}

func (p *Peer) removeResponseHandler(id string) {
	p.lock.Lock()
	defer p.lock.Unlock()
	delete(p.responseHandlers, id)
}

func (p *Peer) getResponseHandler(id string) ResponseHandler {
	p.lock.Lock()
	defer p.lock.Unlock()
	return p.responseHandlers[id]
}
<|endoftext|>


<commit_before>package thermal

import (
	"encoding/json"
)

/*

// seeds from docs:
{
"46fe53c258bbc1984fb5ab02ca1494eccdd54e9688dbbc2c882c8713f1cc4cf3":{
    "admin":"http://github.com/quartzjer",
    "paths":[{"type":"ipv4","ip": "127.0.0.1","port": 42424},{"type":"http","http":"http://127.0.0.1"}],
    "keys":{
      "1a":"z6yCAC7r5XIr6C4xdxeX7RlSmGu9Xe73L1gv8qecm4/UEZAKR5iCxA==",
      "2a":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnDQ/EdMwXn3nAGaEH3bM37xbG71M41iQTnE56xh+RS8kvjAaEG3mxqcezEFyLTuhb8oraoQeHvD8mmCdm+NNpuYUgx3SmnwGO91JsVnVHi94kL5P9UzT501k43nJq+Lnjx5FamFyDDVulAGiOuw4HQHqBuiGsjqQzRO7CclQtlBNewPQUrwoVG7K60+8EIpNuD6opyC6fH1XYNtx10G8hyN1bEyRN+9xsgW3I8Yw8sbPjFhuZGfM0nlgevdG4n+cJaG0fVdag1tx08JiWDlYm3wUWCivLeQTOLKrkVULnPw06YxvWdUURg742avZqMKhZTGsHJgHJir3Tfw9kk0eFwIDAQAB"
    },
    "parts":{
      "1a":"b5a96d25802b3600ea99774138a650d5d1fa1f3cf3cb10ae8f1c58a527d85086",
      "2a":"40a344de8c6e93282d085c577583266e18ed23182d64e382b7e31e05fec57d67"
    }
  }
}

// seeds.json from telehash-c project:
{
  "dca549c98b94197e79dfa2a7e4ad2e74fb144cda3f4710d4f40e2c75d975272e": {
    "paths": [
      {
        "type": "http",
        "http": "http://192.168.0.36:42424"
      },
      {
        "type": "ipv4",
        "ip": "127.0.0.1",
        "port": 42424
      },
      {
        "type": "ipv6",
        "ip": "fe80::bae8:56ff:fe43:3de4",
        "port": 42424
      }
    ],
    "parts": {
      "3a": "f0d2bfc8590a7e0016ce85dbf0f8f1883fb4f3dcc4701eab12ef83f972a2b87f",
      "2a": "0cb4f6137a745f1af2d31707550c03b99083180f6e69ec37918c220ecfa2972f",
      "1a": "b5a96d25802b3600ea99774138a650d5d1fa1f3cf3cb10ae8f1c58a527d85086"
    },
    "keys": {
      "3a": "MC5dfSfrAVCSugX75JbgVWtvCbxPqwLDUkc9TcS/qxE=",
      "2a": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqr12tXnpn707llkZfEcspB/D6KTcZM765+SnI5Z8JWkjc0Mrz9qZBB2YFLr2NmgCx0oLfSetmuHBNTT54sIAxQ/vxyykcMNGsSFg4WKhbsQXSrX4qChbhpIqMJkKa4mYZIb6qONA76G5/431u4+1sBRvfY0ewHChqGh0oThcaa50nT68f8ohIs1iUFm+SL8L9UL/oKN3Yg6drBYwpJi2Ex5Idyu4YQJwZ9sAQU49Pfs+LqhkHOascTmaa3+kTyTnp2iJ9wEuPg+AR3PJwxXnwYoWbH+Wr8gY6iLe0FQe8jXk6eLw9mqOhUcah8338MC83zSQcZriGVMq8qaQz0L9nwIDAQAB",
      "1a": "z6yCAC7r5XIr6C4xdxeX7RlSmGu9Xe73L1gv8qecm4/UEZAKR5iCxA=="
    }
  }
}

*/

type peerLoader1 map[string]peerLoader2

type peerLoader2 struct {
	Admin string
	Paths []pathLoader
	Parts map[string]string
	Keys  map[string]string
}

type pathLoader struct {
	Pathtype string `json:"Type"`
	Ip       string
	Port     int64
	Http     string
}

func loadPeersFromString(peerlist string) []peerSwitch {

	var peers []peerSwitch
	var peerloader peerLoader1

	// unpack each 'seed' in to a peer struct
	json.Unmarshal([]byte(peerlist), &peerloader)
	for hashname, pl2 := range peerloader {

		// map pathLoader(s) to path(s)
		paths := make([]path, 0)
		for _, p := range pl2.Paths {
			paths = append(paths, path{p.Pathtype, p.Ip, p.Port, p.Http})
		}

		peers = append(peers, peerSwitch{hashname, pl2.Admin, paths, pl2.Keys, pl2.Parts})
	}

	return peers
}
<commit_msg>simplify loader<commit_after>package thermal

import (
	"encoding/json"
)

/*

// seeds from docs:
{
"46fe53c258bbc1984fb5ab02ca1494eccdd54e9688dbbc2c882c8713f1cc4cf3":{
    "admin":"http://github.com/quartzjer",
    "paths":[{"type":"ipv4","ip": "127.0.0.1","port": 42424},{"type":"http","http":"http://127.0.0.1"}],
    "keys":{
      "1a":"z6yCAC7r5XIr6C4xdxeX7RlSmGu9Xe73L1gv8qecm4/UEZAKR5iCxA==",
      "2a":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnDQ/EdMwXn3nAGaEH3bM37xbG71M41iQTnE56xh+RS8kvjAaEG3mxqcezEFyLTuhb8oraoQeHvD8mmCdm+NNpuYUgx3SmnwGO91JsVnVHi94kL5P9UzT501k43nJq+Lnjx5FamFyDDVulAGiOuw4HQHqBuiGsjqQzRO7CclQtlBNewPQUrwoVG7K60+8EIpNuD6opyC6fH1XYNtx10G8hyN1bEyRN+9xsgW3I8Yw8sbPjFhuZGfM0nlgevdG4n+cJaG0fVdag1tx08JiWDlYm3wUWCivLeQTOLKrkVULnPw06YxvWdUURg742avZqMKhZTGsHJgHJir3Tfw9kk0eFwIDAQAB"
    },
    "parts":{
      "1a":"b5a96d25802b3600ea99774138a650d5d1fa1f3cf3cb10ae8f1c58a527d85086",
      "2a":"40a344de8c6e93282d085c577583266e18ed23182d64e382b7e31e05fec57d67"
    }
  }
}

// seeds.json from telehash-c project:
{
  "dca549c98b94197e79dfa2a7e4ad2e74fb144cda3f4710d4f40e2c75d975272e": {
    "paths": [
      {
        "type": "http",
        "http": "http://192.168.0.36:42424"
      },
      {
        "type": "ipv4",
        "ip": "127.0.0.1",
        "port": 42424
      },
      {
        "type": "ipv6",
        "ip": "fe80::bae8:56ff:fe43:3de4",
        "port": 42424
      }
    ],
    "parts": {
      "3a": "f0d2bfc8590a7e0016ce85dbf0f8f1883fb4f3dcc4701eab12ef83f972a2b87f",
      "2a": "0cb4f6137a745f1af2d31707550c03b99083180f6e69ec37918c220ecfa2972f",
      "1a": "b5a96d25802b3600ea99774138a650d5d1fa1f3cf3cb10ae8f1c58a527d85086"
    },
    "keys": {
      "3a": "MC5dfSfrAVCSugX75JbgVWtvCbxPqwLDUkc9TcS/qxE=",
      "2a": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqr12tXnpn707llkZfEcspB/D6KTcZM765+SnI5Z8JWkjc0Mrz9qZBB2YFLr2NmgCx0oLfSetmuHBNTT54sIAxQ/vxyykcMNGsSFg4WKhbsQXSrX4qChbhpIqMJkKa4mYZIb6qONA76G5/431u4+1sBRvfY0ewHChqGh0oThcaa50nT68f8ohIs1iUFm+SL8L9UL/oKN3Yg6drBYwpJi2Ex5Idyu4YQJwZ9sAQU49Pfs+LqhkHOascTmaa3+kTyTnp2iJ9wEuPg+AR3PJwxXnwYoWbH+Wr8gY6iLe0FQe8jXk6eLw9mqOhUcah8338MC83zSQcZriGVMq8qaQz0L9nwIDAQAB",
      "1a": "z6yCAC7r5XIr6C4xdxeX7RlSmGu9Xe73L1gv8qecm4/UEZAKR5iCxA=="
    }
  }
}

*/

type peerLoader map[string]struct {
	Admin string
	Paths []pathLoader
	Parts map[string]string
	Keys  map[string]string
}

type pathLoader struct {
	Pathtype string `json:"Type"`
	Ip       string
	Port     int64
	Http     string
}

func loadPeersFromString(peerlist string) []peerSwitch {

	var peers []peerSwitch
	var peerloader peerLoader

	// unpack each 'seed' in to a peer struct
	json.Unmarshal([]byte(peerlist), &peerloader)
	for hashname, pl2 := range peerloader {

		// map pathLoader(s) to path(s)
		paths := make([]path, 0)
		for _, p := range pl2.Paths {
			paths = append(paths, path{p.Pathtype, p.Ip, p.Port, p.Http})
		}

		peers = append(peers, peerSwitch{hashname, pl2.Admin, paths, pl2.Keys, pl2.Parts})
	}

	return peers
}
<|endoftext|>


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

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

package tchannel

import (
	"container/heap"
	"math/rand"
	"sync/atomic"
	"time"
)

// PeerHeap maintains a MIN heap of peers based on the peers' score.
type PeerHeap struct {
	PeerScores []*peerScore
	rng        *rand.Rand
	order      uint64 // atomic
}

func newPeerHeap() *PeerHeap {
	return &PeerHeap{rng: NewRand(time.Now().UnixNano())}
}

func (ph PeerHeap) Len() int { return len(ph.PeerScores) }

func (ph *PeerHeap) Less(i, j int) bool {
	if ph.PeerScores[i].score == ph.PeerScores[j].score {
		return ph.PeerScores[i].order < ph.PeerScores[j].order
	}
	return ph.PeerScores[i].score < ph.PeerScores[j].score
}

func (ph PeerHeap) Swap(i, j int) {
	ph.PeerScores[i], ph.PeerScores[j] = ph.PeerScores[j], ph.PeerScores[i]
	ph.PeerScores[i].index = i
	ph.PeerScores[j].index = j
}

// Push implements heap Push interface
func (ph *PeerHeap) Push(x interface{}) {
	n := len(ph.PeerScores)
	item := x.(*peerScore)
	item.index = n
	ph.PeerScores = append(ph.PeerScores, item)
}

// Pop implements heap Pop interface
func (ph *PeerHeap) Pop() interface{} {
	old := *ph
	n := len(old.PeerScores)
	item := old.PeerScores[n-1]
	item.index = -1 // for safety
	ph.PeerScores = old.PeerScores[:n-1]
	return item
}

//UpdatePeer updates peer at specific index of the heap.
func (ph *PeerHeap) UpdatePeer(peerScore *peerScore) {
	heap.Fix(ph, peerScore.index)
}

// RemovePeer remove peer at specific index.
func (ph *PeerHeap) RemovePeer(peerScore *peerScore) {
	heap.Remove(ph, peerScore.index)
}

// PopPeer pops the top peer of the heap.
func (ph *PeerHeap) PopPeer() *peerScore {
	return heap.Pop(ph).(*peerScore)
}

// PushPeer pushes the new peer into the heap.
func (ph *PeerHeap) PushPeer(peerScore *peerScore) {
	newOrder := atomic.AddUint64(&(ph.order), 1)
	// randRange will affect the deviation of peer's chosenCount
	randRange := ph.Len()/2 + 1
	peerScore.order = newOrder + uint64(ph.rng.Intn(randRange))
	heap.Push(ph, peerScore)
}

// Exposed for testing purposes.
func (ph *PeerHeap) peek() *peerScore {
	return ph.PeerScores[0]
}
<commit_msg>Remove extra parens.<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.

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

package tchannel

import (
	"container/heap"
	"math/rand"
	"sync/atomic"
	"time"
)

// PeerHeap maintains a MIN heap of peers based on the peers' score.
type PeerHeap struct {
	PeerScores []*peerScore
	rng        *rand.Rand
	order      uint64 // atomic
}

func newPeerHeap() *PeerHeap {
	return &PeerHeap{rng: NewRand(time.Now().UnixNano())}
}

func (ph PeerHeap) Len() int { return len(ph.PeerScores) }

func (ph *PeerHeap) Less(i, j int) bool {
	if ph.PeerScores[i].score == ph.PeerScores[j].score {
		return ph.PeerScores[i].order < ph.PeerScores[j].order
	}
	return ph.PeerScores[i].score < ph.PeerScores[j].score
}

func (ph PeerHeap) Swap(i, j int) {
	ph.PeerScores[i], ph.PeerScores[j] = ph.PeerScores[j], ph.PeerScores[i]
	ph.PeerScores[i].index = i
	ph.PeerScores[j].index = j
}

// Push implements heap Push interface
func (ph *PeerHeap) Push(x interface{}) {
	n := len(ph.PeerScores)
	item := x.(*peerScore)
	item.index = n
	ph.PeerScores = append(ph.PeerScores, item)
}

// Pop implements heap Pop interface
func (ph *PeerHeap) Pop() interface{} {
	old := *ph
	n := len(old.PeerScores)
	item := old.PeerScores[n-1]
	item.index = -1 // for safety
	ph.PeerScores = old.PeerScores[:n-1]
	return item
}

//UpdatePeer updates peer at specific index of the heap.
func (ph *PeerHeap) UpdatePeer(peerScore *peerScore) {
	heap.Fix(ph, peerScore.index)
}

// RemovePeer remove peer at specific index.
func (ph *PeerHeap) RemovePeer(peerScore *peerScore) {
	heap.Remove(ph, peerScore.index)
}

// PopPeer pops the top peer of the heap.
func (ph *PeerHeap) PopPeer() *peerScore {
	return heap.Pop(ph).(*peerScore)
}

// PushPeer pushes the new peer into the heap.
func (ph *PeerHeap) PushPeer(peerScore *peerScore) {
	newOrder := atomic.AddUint64(&ph.order, 1)
	// randRange will affect the deviation of peer's chosenCount
	randRange := ph.Len()/2 + 1
	peerScore.order = newOrder + uint64(ph.rng.Intn(randRange))
	heap.Push(ph, peerScore)
}

// Exposed for testing purposes.
func (ph *PeerHeap) peek() *peerScore {
	return ph.PeerScores[0]
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net"
	"net/http"
	"os"
	"strings"
	"text/template"

	socks5 "github.com/armon/go-socks5"
	"github.com/docker/docker/pkg/mflag"
	"github.com/weaveworks/weave/common/mflagext"
)

const (
	pacfile = `
function FindProxyForURL(url, host) {
	if(shExpMatch(host, "*.weave.local")) {
		return "SOCKS5 localhost:8000";
	}
	{{range $key, $value := .}}
	if (host == "{{$key}}") {
		return "SOCKS5 localhost:8000";
	}
	{{end}}
	return "DIRECT";
}
`
)

func main() {
	var as []string
	mflagext.ListVar(&as, []string{"a", "-alias"}, []string{}, "Specify hostname aliases in the form alias:hostname.  Can be repeated.")
	mflag.Parse()

	var aliases = map[string]string{}
	for _, a := range as {
		parts := strings.SplitN(a, ":", 2)
		if len(parts) != 2 {
			fmt.Printf("'%s' is not a valid alias.\n", a)
			mflag.Usage()
			os.Exit(1)
		}
		aliases[parts[0]] = parts[1]
	}

	go socksProxy(aliases)

	t := template.Must(template.New("pacfile").Parse(pacfile))
	http.HandleFunc("/proxy.pac", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/x-ns-proxy-autoconfig")
		t.Execute(w, aliases)
	})

	if err := http.ListenAndServe(":8080", nil); err != nil {
		panic(err)
	}
}

type aliasingResolver struct {
	aliases map[string]string
	socks5.NameResolver
}

func (r aliasingResolver) Resolve(name string) (net.IP, error) {
	if alias, ok := r.aliases[name]; ok {
		return r.NameResolver.Resolve(alias)
	}
	return r.NameResolver.Resolve(name)
}

func socksProxy(aliases map[string]string) {
	conf := &socks5.Config{
		Resolver: aliasingResolver{
			aliases:      aliases,
			NameResolver: socks5.DNSResolver{},
		},
	}
	server, err := socks5.New(conf)
	if err != nil {
		panic(err)
	}
	if err := server.ListenAndServe("tcp", ":8000"); err != nil {
		panic(err)
	}
}
<commit_msg>socks: Make main shExpMatch expression configurable<commit_after>package main

import (
	"fmt"
	"net"
	"net/http"
	"os"
	"strings"
	"text/template"

	socks5 "github.com/armon/go-socks5"
	"github.com/docker/docker/pkg/mflag"
	"github.com/weaveworks/weave/common/mflagext"
)

type pacFileParameters struct {
	HostMatch string
	Aliases   map[string]string
}

const (
	pacfile = `
function FindProxyForURL(url, host) {
	if(shExpMatch(host, "{{.HostMatch}}")) {
		return "SOCKS5 localhost:8000";
	}
	{{range $key, $value := .Aliases}}
	if (host == "{{$key}}") {
		return "SOCKS5 localhost:8000";
	}
	{{end}}
	return "DIRECT";
}
`
)

func main() {
	var (
		as        []string
		hostMatch string
	)
	mflagext.ListVar(&as, []string{"a", "-alias"}, []string{}, "Specify hostname aliases in the form alias:hostname.  Can be repeated.")
	mflag.StringVar(&hostMatch, []string{"h", "-host-match"}, "*.weave.local", "Specify main host shExpMatch expression in pacfile")
	mflag.Parse()

	var aliases = map[string]string{}
	for _, a := range as {
		parts := strings.SplitN(a, ":", 2)
		if len(parts) != 2 {
			fmt.Printf("'%s' is not a valid alias.\n", a)
			mflag.Usage()
			os.Exit(1)
		}
		aliases[parts[0]] = parts[1]
	}

	go socksProxy(aliases)

	t := template.Must(template.New("pacfile").Parse(pacfile))
	http.HandleFunc("/proxy.pac", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/x-ns-proxy-autoconfig")
		t.Execute(w, pacFileParameters{hostMatch, aliases})
	})

	if err := http.ListenAndServe(":8080", nil); err != nil {
		panic(err)
	}
}

type aliasingResolver struct {
	aliases map[string]string
	socks5.NameResolver
}

func (r aliasingResolver) Resolve(name string) (net.IP, error) {
	if alias, ok := r.aliases[name]; ok {
		return r.NameResolver.Resolve(alias)
	}
	return r.NameResolver.Resolve(name)
}

func socksProxy(aliases map[string]string) {
	conf := &socks5.Config{
		Resolver: aliasingResolver{
			aliases:      aliases,
			NameResolver: socks5.DNSResolver{},
		},
	}
	server, err := socks5.New(conf)
	if err != nil {
		panic(err)
	}
	if err := server.ListenAndServe("tcp", ":8000"); err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"github.com/google/go-github/github"
)

// MirroredPR contains the upstream and downstream PR ids
type MirroredPR struct {
	DownstreamID int
	UpstreamID   int
}

// PRMirror contains various different variables
type PRMirror struct {
	GitHubClient  *github.Client
	Context       *context.Context
	Configuration *Config
	Database      *Database
	GitLock       *SpinLock
}

// GitHubEventMonitor passes in an instance of the PRMirror struct to all HTTP calls to the webhook listener
type GitHubEventMonitor struct {
	Mirrorer PRMirror
}

// HandleEvent handles github events and acts like an event handler
func (p PRMirror) HandleEvent(event *github.Event) {
	seenEvent, _ := p.Database.SeenEvent(event.GetID())
	if seenEvent {
		return
	}

	eventType := event.GetType()
	if eventType != "PullRequestEvent" {
		return
	}

	prEvent := github.PullRequestEvent{}
	err := json.Unmarshal(event.GetRawPayload(), &prEvent)
	if err != nil {
		panic(err)
	}

	p.HandlePREvent(&prEvent)
	p.Database.AddEvent(event.GetID())
}

func (p PRMirror) HandlePREvent(prEvent *github.PullRequestEvent) {
	repoName := prEvent.Repo.GetName()
	repoOwner := prEvent.Repo.Owner.GetName()
	prEventURL := prEvent.PullRequest.GetURL()

	if repoName != p.Configuration.UpstreamRepo {
		log.Warningf("Ignoring PR Event: %s because %s != %s\n", prEventURL, repoName, p.Configuration.UpstreamRepo)
		return
	} else if repoOwner != p.Configuration.UpstreamOwner {
		log.Warningf("Ignoring PR Event: %s because %s != %s\n", prEventURL, repoOwner, p.Configuration.UpstreamOwner)
		return
	}

	log.Debugf("Handling PR Event: %s\n", prEventURL)

	prAction := prEvent.GetAction()
	if prAction == "closed" && prEvent.PullRequest.GetMerged() == true {
		prID, err := p.MirrorPR(prEvent.PullRequest)
		if err != nil {
			log.Errorf("Error while creating a new PR: %s\n", err.Error())
		} else {
			p.AddLabels(prID, []string{"Upstream PR Merged"})
			p.Database.StoreMirror(prID, prEvent.PullRequest.GetNumber())
		}
	}
}

// RunEventScraper runs the GitHub repo event API scraper
func (p PRMirror) RunEventScraper() {
	for {
		events, pollInterval, err := p.GetRepoEvents()
		if err == nil {
			for _, event := range events {
				p.HandleEvent(event)
			}
		}

		log.Debugf("Sleeping for %d as specified by GitHub\n", pollInterval)
		time.Sleep(time.Duration(pollInterval) * time.Second)
	}
}

// ServeHTTP handles HTTP requests to the webhook endpoint
func (s GitHubEventMonitor) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	payload, err := github.ValidatePayload(r, []byte(s.Mirrorer.Configuration.WebhookSecret))
	if err != nil {
		log.Errorf("Error validating the payload\n")
		return
	}
	event, err := github.ParseWebHook(github.WebHookType(r), payload)
	if err != nil {
		log.Errorf("Error parsing the payload\n")
	}

	switch event := event.(type) {
	case *github.PullRequestEvent:
		s.Mirrorer.HandlePREvent(event)
	}
}

// RunWebhookListener acts a webhook listener which GitHub will call with events
func (p PRMirror) RunWebhookListener() {
	server := GitHubEventMonitor{Mirrorer: p}
	err := http.ListenAndServe(fmt.Sprintf(":%d", p.Configuration.WebhookPort), server)
	log.Fatal(err)
}

// MirrorPR will mirror a PR from an upstream to the downstream
func (p PRMirror) MirrorPR(pr *github.PullRequest) (int, error) {
	p.GitLock.Lock()
	defer p.GitLock.Unlock()

	log.Infof("Mirroring PR [%d]: %s from %s\n", pr.GetNumber(), pr.GetTitle(), pr.User.GetLogin())

	cmd := exec.Command(fmt.Sprintf("%s%s", p.Configuration.RepoPath, p.Configuration.ToolPath), strconv.Itoa(pr.GetNumber()), pr.GetTitle())
	cmd.Dir = p.Configuration.RepoPath
	cmdoutput, err := cmd.CombinedOutput()
	if err != nil {
		panic(err)
	}

	logpath := fmt.Sprintf("./logs/upstream-merge-%d.log", pr.GetNumber())
	ioutil.WriteFile(logpath, cmdoutput, 0600)
	log.Debugf("Wrote log to %s\n", logpath)

	base := "master"
	head := fmt.Sprintf("upstream-merge-%d", pr.GetNumber())
	maintainerCanModify := true // We are the owner of the PR so we can specify this as true
	title := fmt.Sprintf("[MIRROR] %s", pr.GetTitle())
	body := fmt.Sprintf("Original PR: %s\n--------------------\n%s", pr.GetHTMLURL(), strings.Replace(pr.GetBody(), "@", "@ ", -1))

	newPR := github.NewPullRequest{}
	newPR.Title = &title
	newPR.Body = &body
	newPR.Base = &base
	newPR.Head = &head
	newPR.MaintainerCanModify = &maintainerCanModify

	pr, _, err = p.GitHubClient.PullRequests.Create(*p.Context, p.Configuration.DownstreamOwner, p.Configuration.DownstreamRepo, &newPR)
	if err != nil {
		return 0, err
	}

	if strings.Contains(string(cmdoutput), "Rejected hunk") {
		p.AddLabels(pr.GetNumber(), []string{"Auto Merge Rejections"})
	}

	return pr.GetNumber(), nil
}
<commit_msg>fucking wow<commit_after>package main

import (
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"github.com/google/go-github/github"
)

// MirroredPR contains the upstream and downstream PR ids
type MirroredPR struct {
	DownstreamID int
	UpstreamID   int
}

// PRMirror contains various different variables
type PRMirror struct {
	GitHubClient  *github.Client
	Context       *context.Context
	Configuration *Config
	Database      *Database
	GitLock       *SpinLock
}

// GitHubEventMonitor passes in an instance of the PRMirror struct to all HTTP calls to the webhook listener
type GitHubEventMonitor struct {
	Mirrorer PRMirror
}

// HandleEvent handles github events and acts like an event handler
func (p PRMirror) HandleEvent(event *github.Event) {
	seenEvent, _ := p.Database.SeenEvent(event.GetID())
	if seenEvent {
		return
	}

	eventType := event.GetType()
	if eventType != "PullRequestEvent" {
		return
	}

	prEvent := github.PullRequestEvent{}
	err := json.Unmarshal(event.GetRawPayload(), &prEvent)
	if err != nil {
		panic(err)
	}

	p.HandlePREvent(&prEvent)
	p.Database.AddEvent(event.GetID())
}

func (p PRMirror) HandlePREvent(prEvent *github.PullRequestEvent) {
	repoName := prEvent.Repo.GetName()
	repoOwner := prEvent.Repo.Organization.GetName()
	prEventURL := prEvent.PullRequest.GetURL()

	if repoName != p.Configuration.UpstreamRepo {
		log.Warningf("Ignoring PR Event: %s because %s != %s\n", prEventURL, repoName, p.Configuration.UpstreamRepo)
		return
	} else if repoOwner != p.Configuration.UpstreamOwner {
		log.Warningf("Ignoring PR Event: %s because %s != %s\n", prEventURL, repoOwner, p.Configuration.UpstreamOwner)
		return
	}

	log.Debugf("Handling PR Event: %s\n", prEventURL)

	prAction := prEvent.GetAction()
	if prAction == "closed" && prEvent.PullRequest.GetMerged() == true {
		prID, err := p.MirrorPR(prEvent.PullRequest)
		if err != nil {
			log.Errorf("Error while creating a new PR: %s\n", err.Error())
		} else {
			p.AddLabels(prID, []string{"Upstream PR Merged"})
			p.Database.StoreMirror(prID, prEvent.PullRequest.GetNumber())
		}
	}
}

// RunEventScraper runs the GitHub repo event API scraper
func (p PRMirror) RunEventScraper() {
	for {
		events, pollInterval, err := p.GetRepoEvents()
		if err == nil {
			for _, event := range events {
				p.HandleEvent(event)
			}
		}

		log.Debugf("Sleeping for %d as specified by GitHub\n", pollInterval)
		time.Sleep(time.Duration(pollInterval) * time.Second)
	}
}

// ServeHTTP handles HTTP requests to the webhook endpoint
func (s GitHubEventMonitor) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	payload, err := github.ValidatePayload(r, []byte(s.Mirrorer.Configuration.WebhookSecret))
	if err != nil {
		log.Errorf("Error validating the payload\n")
		return
	}
	event, err := github.ParseWebHook(github.WebHookType(r), payload)
	if err != nil {
		log.Errorf("Error parsing the payload\n")
	}

	switch event := event.(type) {
	case *github.PullRequestEvent:
		s.Mirrorer.HandlePREvent(event)
	}
}

// RunWebhookListener acts a webhook listener which GitHub will call with events
func (p PRMirror) RunWebhookListener() {
	server := GitHubEventMonitor{Mirrorer: p}
	err := http.ListenAndServe(fmt.Sprintf(":%d", p.Configuration.WebhookPort), server)
	log.Fatal(err)
}

// MirrorPR will mirror a PR from an upstream to the downstream
func (p PRMirror) MirrorPR(pr *github.PullRequest) (int, error) {
	p.GitLock.Lock()
	defer p.GitLock.Unlock()

	log.Infof("Mirroring PR [%d]: %s from %s\n", pr.GetNumber(), pr.GetTitle(), pr.User.GetLogin())

	cmd := exec.Command(fmt.Sprintf("%s%s", p.Configuration.RepoPath, p.Configuration.ToolPath), strconv.Itoa(pr.GetNumber()), pr.GetTitle())
	cmd.Dir = p.Configuration.RepoPath
	cmdoutput, err := cmd.CombinedOutput()
	if err != nil {
		panic(err)
	}

	logpath := fmt.Sprintf("./logs/upstream-merge-%d.log", pr.GetNumber())
	ioutil.WriteFile(logpath, cmdoutput, 0600)
	log.Debugf("Wrote log to %s\n", logpath)

	base := "master"
	head := fmt.Sprintf("upstream-merge-%d", pr.GetNumber())
	maintainerCanModify := true // We are the owner of the PR so we can specify this as true
	title := fmt.Sprintf("[MIRROR] %s", pr.GetTitle())
	body := fmt.Sprintf("Original PR: %s\n--------------------\n%s", pr.GetHTMLURL(), strings.Replace(pr.GetBody(), "@", "@ ", -1))

	newPR := github.NewPullRequest{}
	newPR.Title = &title
	newPR.Body = &body
	newPR.Base = &base
	newPR.Head = &head
	newPR.MaintainerCanModify = &maintainerCanModify

	pr, _, err = p.GitHubClient.PullRequests.Create(*p.Context, p.Configuration.DownstreamOwner, p.Configuration.DownstreamRepo, &newPR)
	if err != nil {
		return 0, err
	}

	if strings.Contains(string(cmdoutput), "Rejected hunk") {
		p.AddLabels(pr.GetNumber(), []string{"Auto Merge Rejections"})
	}

	return pr.GetNumber(), nil
}
<|endoftext|>


<commit_before><commit_msg>add wechat pay<commit_after><|endoftext|>


<commit_before>package main

import (
	"os"
	"path/filepath"
	"strings"
	"time"

	"bazil.org/fuse"
	"bazil.org/fuse/fs"
	"golang.org/x/net/context"
)

type Dir struct {
	*Node

	// Parent is pointer to Dir that holds this Dir. Each File/Dir has single
	// parent; a parent can have multiple children.
	Parent *Dir

	// EntriesList contains list of files and directories belong to this Dir.
	EntriesList map[string]*Node

	// fuseEntries contains cache for `fs.ReadDirAll` request to Transport.
	// TODO: need a better name
	FuseEntries []fuse.Dirent
}

func NewDir(n *Node) *Dir {
	return &Dir{Node: n, EntriesList: map[string]*Node{}}
}

// Lookup returns file or dir if exists; fuse.EEXIST if not. Required by Fuse.
func (d *Dir) Lookup(ctx context.Context, name string) (fs.Node, error) {
	d.RLock()
	defer d.RUnlock()

	n := NewNode(d, name)

	// TODO: how to deal with resource files
	if strings.HasPrefix(name, "._") {
		return n, nil
	}

	// debug should almost be the first statement, but to prevent spamming of
	// resource file lookups, this call is moved here
	defer debug(time.Now(), "Lookup="+name)

	// get entry from cache, return if it exists
	if n, ok := d.EntriesList[name]; ok {
		if n.DirentType == fuse.DT_Dir {
			return NewDir(n), nil
		}

		return &File{Parent: d, Node: n}, nil
	}

	res, err := n.getInfo()
	if err != nil {
		return nil, err
	}

	n.attr.Size = uint64(res.Size)
	n.attr.Mode = os.FileMode(res.Mode)

	// TODO: set node in Dir#EntriesList and Dir#fuseEntries?

	if res.IsDir {
		return NewDir(n), nil
	}

	return &File{Parent: d, Node: n}, nil
}

// ReadDirAll returns metadata for files and directories. Required by Fuse.
// TODO: this method seems to be called way too many times in short period.
func (d *Dir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
	defer debug(time.Now(), "Dir="+d.Name)

	d.RLock()
	entries := d.FuseEntries
	d.RUnlock()

	if len(entries) != 0 {
		return entries, nil
	}

	return d.readDirAll()
}

func (d *Dir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (fs.Node, fs.Handle, error) {
	n := NewNode(d, req.Name)

	_, err := n.getInfo()
	if err != nil && err != fuse.ENOENT {
		return nil, nil, err
	}

	f := &File{Parent: d, Node: n}

	if err == fuse.ENOENT {
		err = f.write([]byte{})
	}

	return f, f, err
}

// Mkdir creates new directory under inside Dir. Required by Fuse.
func (d *Dir) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error) {
	defer debug(time.Now(), "Dir="+req.Name)

	treq := struct {
		Path      string
		Recursive bool
	}{
		Path:      filepath.Join(d.ExternalPath, req.Name),
		Recursive: true,
	}
	var tres bool

	if err := d.Trip("fs.createDirectory", treq, &tres); err != nil {
		return nil, err
	}

	if err := d.invalidateCache(req.Name); err != nil {
		return nil, err
	}

	// TODO: make `fs.createDirectory` to return folder info in creation
	n := NewNode(d, req.Name)
	res, err := n.getInfo()
	if err != nil {
		return nil, err
	}

	n.attr.Size = uint64(res.Size)
	n.attr.Mode = os.FileMode(res.Mode)

	return &Dir{Parent: d, Node: n}, nil
}

// Remove deletes File or Dir. Required by Fuse.
func (d *Dir) Remove(ctx context.Context, req *fuse.RemoveRequest) error {
	defer debug(time.Now(), "Dir="+req.Name)

	treq := struct {
		Path      string
		Recursive bool
	}{
		Path:      filepath.Join(d.ExternalPath, req.Name),
		Recursive: true,
	}
	var tres bool

	if err := d.Trip("fs.remove", treq, &tres); err != nil {
		return err
	}

	return d.invalidateCache(req.Name)
}

// Rename changes name of File or Dir. Required by Fuse.
func (d *Dir) Rename(ctx context.Context, req *fuse.RenameRequest, newDir fs.Node) error {
	defer debug(time.Now(), "OldPath="+req.OldName, "NewPath="+req.NewName)

	treq := struct{ OldPath, NewPath string }{
		OldPath: filepath.Join(d.ExternalPath, req.OldName),
		NewPath: filepath.Join(d.ExternalPath, req.NewName),
	}
	var tres bool

	if err := d.Trip("fs.rename", treq, &tres); err != nil {
		return err
	}

	return d.invalidateCache(req.OldName)
}

func (d *Dir) readDirAll() ([]fuse.Dirent, error) {
	d.Lock()
	defer d.Unlock()

	req := struct{ Path string }{d.ExternalPath}
	res := fsReadDirectoryRes{}

	if err := d.Trip("fs.readDirectory", req, &res); err != nil {
		return nil, err
	}

	d.EntriesList = map[string]*Node{}

	var dirents []fuse.Dirent
	for _, file := range res.Files {
		ent := fuse.Dirent{Name: file.Name, Type: fuse.DT_File}
		if file.IsDir {
			ent.Type = fuse.DT_Dir
		}
		dirents = append(dirents, ent)

		n := NewNode(d, file.Name)
		n.DirentType = ent.Type
		n.attr.Size = uint64(file.Size)
		n.attr.Mode = os.FileMode(file.Mode)

		// cache entries to save on Node#Attr requests
		d.EntriesList[file.Name] = n
	}

	// cache entries to save on repeated calls
	d.FuseEntries = dirents

	return dirents, nil
}

// invalidateCache removes cache, which will trigger lookup in Transport on next
// request to be used on write operations; to be used in write operations.
//
// TODO: be smarter about invalidating cache, ie delete entry and do lookup.
func (d *Dir) invalidateCache(entry string) error {
	_, err := d.readDirAll()
	return err
}
<commit_msg>use read locks when accessing keys in Dir<commit_after>package main

import (
	"os"
	"path/filepath"
	"strings"
	"time"

	"bazil.org/fuse"
	"bazil.org/fuse/fs"
	"golang.org/x/net/context"
)

type Dir struct {
	*Node

	// Parent is pointer to Dir that holds this Dir. Each File/Dir has single
	// parent; a parent can have multiple children.
	Parent *Dir

	// EntriesList contains list of files and directories belong to this Dir.
	EntriesList map[string]*Node

	// fuseEntries contains cache for `fs.ReadDirAll` request to Transport.
	// TODO: need a better name
	FuseEntries []fuse.Dirent
}

func NewDir(n *Node) *Dir {
	return &Dir{Node: n, EntriesList: map[string]*Node{}}
}

// Lookup returns file or dir if exists; fuse.EEXIST if not. Required by Fuse.
func (d *Dir) Lookup(ctx context.Context, name string) (fs.Node, error) {
	d.RLock()
	defer d.RUnlock()

	n := NewNode(d, name)

	// TODO: how to deal with resource files
	if strings.HasPrefix(name, "._") {
		return n, nil
	}

	// debug should almost be the first statement, but to prevent spamming of
	// resource file lookups, this call is moved here
	defer debug(time.Now(), "Lookup="+name)

	// get entry from cache, return if it exists
	if n, ok := d.EntriesList[name]; ok {
		if n.DirentType == fuse.DT_Dir {
			return NewDir(n), nil
		}

		return &File{Parent: d, Node: n}, nil
	}

	res, err := n.getInfo()
	if err != nil {
		return nil, err
	}

	n.attr.Size = uint64(res.Size)
	n.attr.Mode = os.FileMode(res.Mode)

	// TODO: set node in Dir#EntriesList and Dir#fuseEntries?

	if res.IsDir {
		return NewDir(n), nil
	}

	return &File{Parent: d, Node: n}, nil
}

// ReadDirAll returns metadata for files and directories. Required by Fuse.
// TODO: this method seems to be called way too many times in short period.
func (d *Dir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
	defer debug(time.Now(), "Dir="+d.Name)

	d.RLock()
	entries := d.FuseEntries
	d.RUnlock()

	if len(entries) != 0 {
		return entries, nil
	}

	return d.readDirAll()
}

func (d *Dir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (fs.Node, fs.Handle, error) {
	d.RLock()
	n := NewNode(d, req.Name)
	d.RUnlock()

	f := &File{Parent: d, Node: n}

	var err error
	if _, err = n.getInfo(); err != nil && err != fuse.ENOENT {
		return nil, nil, err
	}

	// only write if file doesn't already exist
	if err == fuse.ENOENT {
		if err := f.write([]byte{}); err != nil {
			return nil, nil, err
		}
	}

	if err := d.invalidateCache(req.Name); err != nil {
		return nil, nil, err
	}

	return f, f, nil
}

// Mkdir creates new directory under inside Dir. Required by Fuse.
func (d *Dir) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error) {
	defer debug(time.Now(), "Dir="+req.Name)

	d.RLock()
	path := filepath.Join(d.ExternalPath, req.Name)
	d.RUnlock()

	treq := struct {
		Path      string
		Recursive bool
	}{
		Path:      path,
		Recursive: true,
	}
	var tres bool

	if err := d.Trip("fs.createDirectory", treq, &tres); err != nil {
		return nil, err
	}

	if err := d.invalidateCache(req.Name); err != nil {
		return nil, err
	}

	// TODO: make `fs.createDirectory` to return folder info in creation
	n := NewNode(d, req.Name)
	res, err := n.getInfo()
	if err != nil {
		return nil, err
	}

	n.attr.Size = uint64(res.Size)
	n.attr.Mode = os.FileMode(res.Mode)

	return &Dir{Parent: d, Node: n}, nil
}

// Remove deletes File or Dir. Required by Fuse.
func (d *Dir) Remove(ctx context.Context, req *fuse.RemoveRequest) error {
	defer debug(time.Now(), "Dir="+req.Name)

	d.RLock()
	path := filepath.Join(d.ExternalPath, req.Name)
	d.RUnlock()

	treq := struct {
		Path      string
		Recursive bool
	}{
		Path:      path,
		Recursive: true,
	}
	var tres bool

	if err := d.Trip("fs.remove", treq, &tres); err != nil {
		return err
	}

	return d.invalidateCache(req.Name)
}

// Rename changes name of File or Dir. Required by Fuse.
func (d *Dir) Rename(ctx context.Context, req *fuse.RenameRequest, newDir fs.Node) error {
	defer debug(time.Now(), "OldPath="+req.OldName, "NewPath="+req.NewName)

	d.RLock()
	path := d.ExternalPath
	d.RUnlock()

	treq := struct{ OldPath, NewPath string }{
		OldPath: filepath.Join(path, req.OldName),
		NewPath: filepath.Join(path, req.NewName),
	}
	var tres bool

	if err := d.Trip("fs.rename", treq, &tres); err != nil {
		return err
	}

	return d.invalidateCache(req.OldName)
}

func (d *Dir) readDirAll() ([]fuse.Dirent, error) {
	d.Lock()
	defer d.Unlock()

	req := struct{ Path string }{d.ExternalPath}
	res := fsReadDirectoryRes{}

	if err := d.Trip("fs.readDirectory", req, &res); err != nil {
		return nil, err
	}

	d.EntriesList = map[string]*Node{}

	var dirents []fuse.Dirent
	for _, file := range res.Files {
		ent := fuse.Dirent{Name: file.Name, Type: fuse.DT_File}
		if file.IsDir {
			ent.Type = fuse.DT_Dir
		}
		dirents = append(dirents, ent)

		n := NewNode(d, file.Name)
		n.DirentType = ent.Type
		n.attr.Size = uint64(file.Size)
		n.attr.Mode = os.FileMode(file.Mode)

		// cache entries to save on Node#Attr requests
		d.EntriesList[file.Name] = n
	}

	// cache entries to save on repeated calls
	d.FuseEntries = dirents

	return dirents, nil
}

// invalidateCache removes cache, which will trigger lookup in Transport on next
// request to be used on write operations; to be used in write operations.
//
// TODO: be smarter about invalidating cache, ie delete entry and do lookup.
func (d *Dir) invalidateCache(entry string) error {
	_, err := d.readDirAll()
	return err
}
<|endoftext|>