<commit_before>package config_test

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"testing"

	"github.com/fly/config"
)

type testConfig struct {
	Example []string `yaml:"example"`
}

type burritoConfig struct {
	Location string `yaml:"location"`
	Burritos bool   `yaml:"burritos"`
}

// TODO: come up with a way to test homedir without hardcoding travis
const (
	correctEnvVar string = "TESTORG_TESTSYSTEM_CONFIG_URI"
	systemBaseDir string = "/etc/"
	systemDir     string = "/etc/testorg/testsystem/"
	systemPath    string = "/etc/testorg/testsystem/config.yaml"
	userBaseDir   string = "/home/travis/.config/"
	userDir       string = "/home/travis/"
	userPath      string = "/home/travis/.config/testorg/testsystem/config.yaml"
	organization  string = "testorg"
	system        string = "testsystem"
)

const (
	dirMode  os.FileMode = 0755
	fileMode os.FileMode = 0644
)

var cfgNS = config.Namespace{
	Organization: organization,
	System:       system,
}

// In this example our organization is named "testorganization", and our project
// namespace is "testsystem".
//
// In this example we have a file located at
// /Users/jchen/.config/testorg/testsystem/config.yaml with the
// following contents:
//  example:
//    - "a"
//    - "b"
//    - "c"
func ExampleNamespace() {
	var err error
	var cfg testConfig
	var path string

	path = cfgNS.Path()
	fmt.Println("Path to config " + path)

	err = cfgNS.Load(&cfg)
	if err != nil {
		log.Fatalln(err)
	}
	fmt.Println("Contents of cfg " + fmt.Sprint(cfg))
}

func TestExpandUser(t *testing.T) {
	var path string
	correctPath := userPath

	path = config.ExpandUser("~/.config/testorg/testsystem/config.yaml")

	if path != correctPath {
		t.Error("Expected ", correctPath, ", got ", path)
	}

	path = config.ExpandUser("$HOME/.config/testorg/testsystem/config.yaml")

	if path != correctPath {
		t.Error("Expected ", correctPath, ", got ", path)
	}
}

func TestLoad(t *testing.T) {
	correctDir := systemDir
	correctPath := systemPath
	var correctCfgText = `location: Señor Sisig
burritos: true`
	var correctCfg = burritoConfig{
		Location: "Señor Sisig",
		Burritos: true,
	}
	var err error
	var cfg burritoConfig

	// Setup
	err = os.RemoveAll(userPath)
	if err != nil {
		t.Error("Got an error removing ", userPath, ": ", err)
	}

	err = os.MkdirAll(correctDir, dirMode)
	if err != nil {
		t.Error("Got an error creating ", correctDir, ": ", err)
	}

	err = ioutil.WriteFile(correctPath, []byte(correctCfgText), fileMode)
	if err != nil {
		t.Error("Got an error writing ", correctPath, ": ", err)
	}

	// Test
	err = config.Load(correctPath, &cfg)
	if err != nil {
		t.Error("Got an error: ", err, ", expecting nil")
	}

	if cfg != correctCfg {
		t.Error("Expecting ", correctCfg, ", got ", cfg)
	}

	err = config.Load(correctPath, cfg)
	if err.Error() != "config: not a pointer" {
		t.Error("Expecting error: config: not a pointer, instead got", err)
	}

	err = config.Load("rumpelstilzjchen", &cfg)
	if err == nil {
		t.Error("Expected read error, got nil")
	}

	// Teardown
	err = os.RemoveAll(correctPath)
	if err != nil {
		t.Error("Unable to remove file ", correctPath,
			" in teardown, got an error: ", err)
	}
}

func TestUserBase(t *testing.T) {
	userbase := "~/.config/"
	if config.UserBase != userbase {
		t.Error("Expecting ", userbase, ", got ", config.UserBase)
	}
}

func TestSystemBase(t *testing.T) {
	if config.SystemBase != systemBaseDir {
		t.Error("Expecting ", systemBaseDir, ", got ", config.SystemBase)
	}
}

func TestNamespacePath(t *testing.T) {
	var err error
	var path string

	correctDir := systemDir
	correctPath := systemPath

	// Setup
	err = os.RemoveAll(userPath)
	if err != nil {
		t.Error("Unable to remove file ", correctPath, ", got an error: ", err)
	}

	err = os.MkdirAll(correctDir, dirMode)
	if err != nil {
		t.Error("Unable to create directory ", correctPath, ", got an error: ", err)
	}

	_, err = os.Create(correctPath)
	if err != nil {
		t.Error("Unable to create file ", correctPath, ", got an error: ", err)
	}

	// Test
	path = cfgNS.Path()
	if path != correctPath {
		t.Error("Expecting ", correctPath, ", got ", path)
	}

	// Teardown
	err = os.RemoveAll(correctPath)
	if err != nil {
		t.Error("Unable to remove file ", correctPath,
			" in teardown, got an error: ", err)
	}

	// test homedir
	// Setup
	correctDir = userDir
	correctPath = userPath
	err = os.RemoveAll(systemPath)
	if err != nil {
		t.Error("Unable to remove file ", correctPath, ", got an error: ", err)
	}

	err = os.MkdirAll(correctDir, dirMode)
	if err != nil {
		t.Error("Unable to create directory ", correctPath, ", got an error: ", err)
	}

	_, err = os.Create(correctPath)
	if err != nil {
		t.Error("Unable to create file ", correctPath, ", got an error: ", err)
	}

	// Test
	path = cfgNS.Path()
	if path != correctPath {
		t.Error("Expecting ", correctPath, ", got ", path)
	}

	// Teardown
	err = os.RemoveAll(correctPath)
	if err != nil {
		t.Error("Unable to remove file ", correctPath,
			" in teardown, got an error: ", err)
	}
}

func TestNamespaceEnvVar(t *testing.T) {
	if cfgNS.EnvVar() != correctEnvVar {
		t.Error("Expecting ", correctEnvVar, ", got ", cfgNS.EnvVar())
	}
}

func TestNewConfigFromNamespace(t *testing.T) {
	const (
		organization = "fly"
		system       = "config"
	)

	var err error

	correctDir := systemDir
	correctPath := systemPath

	// Setup
	err = os.RemoveAll(userPath)
	if err != nil {
		t.Error("Unable to remove file ", userPath, ", got an error: ", err)
	}

	err = os.MkdirAll(correctDir, dirMode)
	if err != nil {
		t.Error("Unable to create directory ", correctPath, ", got an error: ", err)
	}

	_, err = os.Create(correctPath)
	if err != nil {
		t.Error("Unable to create file ", correctPath, ", got an error: ", err)
	}

	_, err = config.NewConfigFromNamespace(organization, system)
	if err != nil {
		t.Error("Expecting no error, got", err)
	}

	err = os.RemoveAll(correctPath)
	if err != nil {
		t.Error("Unable to remove file ", correctPath,
			" in teardown, got an error: ", err)
	}
}

func TestNamespaceLoad(t *testing.T) {
	correctDir := systemDir
	correctPath := systemPath

	correctCfgText := `location: Señor Sisig
burritos: true`
	correctCfg := burritoConfig{
		Location: "Señor Sisig",
		Burritos: true,
	}
	var err error
	var cfg burritoConfig

	// Setup
	err = os.RemoveAll(userPath)
	if err != nil {
		t.Error("Unable to remove path ", correctPath, ", got an error: ", err)
	}

	err = os.MkdirAll(correctDir, dirMode)
	if err != nil {
		t.Error("Unable to create directory ", correctPath, ", got an error: ", err)
	}

	err = ioutil.WriteFile(correctPath, []byte(correctCfgText), fileMode)
	if err != nil {
		t.Error("Got an error writing ", correctPath, ": ", err)
	}

	// Test
	err = cfgNS.Load(&cfg)
	if err != nil {
		t.Error("Got an error: ", err, ", expecting nil")
	}

	if cfg != correctCfg {
		t.Error("Expecting ", correctCfg, ", got ", cfg)
	}

	// Teardown
	err = os.RemoveAll(correctPath)
	if err != nil {
		t.Error("Unable to remove file ", correctPath,
			" in teardown, got an error: ", err)
	}
}
<commit_msg>use correct test names<commit_after>package config_test

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"testing"

	"github.com/fly/config"
)

type testConfig struct {
	Example []string `yaml:"example"`
}

type burritoConfig struct {
	Location string `yaml:"location"`
	Burritos bool   `yaml:"burritos"`
}

// TODO: come up with a way to test homedir without hardcoding travis
const (
	correctEnvVar string = "TESTORG_TESTSYSTEM_CONFIG_URI"
	systemBaseDir string = "/etc/"
	systemDir     string = "/etc/testorg/testsystem/"
	systemPath    string = "/etc/testorg/testsystem/config.yaml"
	userBaseDir   string = "/home/travis/.config/"
	userDir       string = "/home/travis/"
	userPath      string = "/home/travis/.config/testorg/testsystem/config.yaml"
	organization  string = "testorg"
	system        string = "testsystem"
)

const (
	dirMode  os.FileMode = 0755
	fileMode os.FileMode = 0644
)

var cfgNS = config.Namespace{
	Organization: organization,
	System:       system,
}

// In this example our organization is named "testorganization", and our project
// namespace is "testsystem".
//
// In this example we have a file located at
// /Users/jchen/.config/testorg/testsystem/config.yaml with the
// following contents:
//  example:
//    - "a"
//    - "b"
//    - "c"
func ExampleNamespace() {
	var err error
	var cfg testConfig
	var path string

	path = cfgNS.Path()
	fmt.Println("Path to config " + path)

	err = cfgNS.Load(&cfg)
	if err != nil {
		log.Fatalln(err)
	}
	fmt.Println("Contents of cfg " + fmt.Sprint(cfg))
}

func TestExpandUser(t *testing.T) {
	var path string
	correctPath := userPath

	path = config.ExpandUser("~/.config/testorg/testsystem/config.yaml")

	if path != correctPath {
		t.Error("Expected ", correctPath, ", got ", path)
	}

	path = config.ExpandUser("$HOME/.config/testorg/testsystem/config.yaml")

	if path != correctPath {
		t.Error("Expected ", correctPath, ", got ", path)
	}
}

func TestLoad(t *testing.T) {
	correctDir := systemDir
	correctPath := systemPath
	var correctCfgText = `location: Señor Sisig
burritos: true`
	var correctCfg = burritoConfig{
		Location: "Señor Sisig",
		Burritos: true,
	}
	var err error
	var cfg burritoConfig

	// Setup
	err = os.RemoveAll(userPath)
	if err != nil {
		t.Error("Got an error removing ", userPath, ": ", err)
	}

	err = os.MkdirAll(correctDir, dirMode)
	if err != nil {
		t.Error("Got an error creating ", correctDir, ": ", err)
	}

	err = ioutil.WriteFile(correctPath, []byte(correctCfgText), fileMode)
	if err != nil {
		t.Error("Got an error writing ", correctPath, ": ", err)
	}

	// Test
	err = config.Load(correctPath, &cfg)
	if err != nil {
		t.Error("Got an error: ", err, ", expecting nil")
	}

	if cfg != correctCfg {
		t.Error("Expecting ", correctCfg, ", got ", cfg)
	}

	err = config.Load(correctPath, cfg)
	if err.Error() != "config: not a pointer" {
		t.Error("Expecting error: config: not a pointer, instead got", err)
	}

	err = config.Load("rumpelstilzjchen", &cfg)
	if err == nil {
		t.Error("Expected read error, got nil")
	}

	// Teardown
	err = os.RemoveAll(correctPath)
	if err != nil {
		t.Error("Unable to remove file ", correctPath,
			" in teardown, got an error: ", err)
	}
}

func TestUserBase(t *testing.T) {
	userbase := "~/.config/"
	if config.UserBase != userbase {
		t.Error("Expecting ", userbase, ", got ", config.UserBase)
	}
}

func TestSystemBase(t *testing.T) {
	if config.SystemBase != systemBaseDir {
		t.Error("Expecting ", systemBaseDir, ", got ", config.SystemBase)
	}
}

func TestNamespacePath(t *testing.T) {
	var err error
	var path string

	correctDir := systemDir
	correctPath := systemPath

	// Setup
	err = os.RemoveAll(userPath)
	if err != nil {
		t.Error("Unable to remove file ", correctPath, ", got an error: ", err)
	}

	err = os.MkdirAll(correctDir, dirMode)
	if err != nil {
		t.Error("Unable to create directory ", correctPath, ", got an error: ", err)
	}

	_, err = os.Create(correctPath)
	if err != nil {
		t.Error("Unable to create file ", correctPath, ", got an error: ", err)
	}

	// Test
	path = cfgNS.Path()
	if path != correctPath {
		t.Error("Expecting ", correctPath, ", got ", path)
	}

	// Teardown
	err = os.RemoveAll(correctPath)
	if err != nil {
		t.Error("Unable to remove file ", correctPath,
			" in teardown, got an error: ", err)
	}

	// test homedir
	// Setup
	correctDir = userDir
	correctPath = userPath
	err = os.RemoveAll(systemPath)
	if err != nil {
		t.Error("Unable to remove file ", correctPath, ", got an error: ", err)
	}

	err = os.MkdirAll(correctDir, dirMode)
	if err != nil {
		t.Error("Unable to create directory ", correctPath, ", got an error: ", err)
	}

	_, err = os.Create(correctPath)
	if err != nil {
		t.Error("Unable to create file ", correctPath, ", got an error: ", err)
	}

	// Test
	path = cfgNS.Path()
	if path != correctPath {
		t.Error("Expecting ", correctPath, ", got ", path)
	}

	// Teardown
	err = os.RemoveAll(correctPath)
	if err != nil {
		t.Error("Unable to remove file ", correctPath,
			" in teardown, got an error: ", err)
	}
}

func TestNamespaceEnvVar(t *testing.T) {
	if cfgNS.EnvVar() != correctEnvVar {
		t.Error("Expecting ", correctEnvVar, ", got ", cfgNS.EnvVar())
	}
}

func TestNewConfigFromNamespace(t *testing.T) {
	const (
		organization = "testorg"
		system       = "testsystem"
	)

	var err error

	correctDir := systemDir
	correctPath := systemPath

	// Setup
	err = os.RemoveAll(userPath)
	if err != nil {
		t.Error("Unable to remove file ", userPath, ", got an error: ", err)
	}

	err = os.MkdirAll(correctDir, dirMode)
	if err != nil {
		t.Error("Unable to create directory ", correctPath, ", got an error: ", err)
	}

	_, err = os.Create(correctPath)
	if err != nil {
		t.Error("Unable to create file ", correctPath, ", got an error: ", err)
	}

	_, err = config.NewConfigFromNamespace(organization, system)
	if err != nil {
		t.Error("Expecting no error, got", err)
	}

	err = os.RemoveAll(correctPath)
	if err != nil {
		t.Error("Unable to remove file ", correctPath,
			" in teardown, got an error: ", err)
	}
}

func TestNamespaceLoad(t *testing.T) {
	correctDir := systemDir
	correctPath := systemPath

	correctCfgText := `location: Señor Sisig
burritos: true`
	correctCfg := burritoConfig{
		Location: "Señor Sisig",
		Burritos: true,
	}
	var err error
	var cfg burritoConfig

	// Setup
	err = os.RemoveAll(userPath)
	if err != nil {
		t.Error("Unable to remove path ", correctPath, ", got an error: ", err)
	}

	err = os.MkdirAll(correctDir, dirMode)
	if err != nil {
		t.Error("Unable to create directory ", correctPath, ", got an error: ", err)
	}

	err = ioutil.WriteFile(correctPath, []byte(correctCfgText), fileMode)
	if err != nil {
		t.Error("Got an error writing ", correctPath, ": ", err)
	}

	// Test
	err = cfgNS.Load(&cfg)
	if err != nil {
		t.Error("Got an error: ", err, ", expecting nil")
	}

	if cfg != correctCfg {
		t.Error("Expecting ", correctCfg, ", got ", cfg)
	}

	// Teardown
	err = os.RemoveAll(correctPath)
	if err != nil {
		t.Error("Unable to remove file ", correctPath,
			" in teardown, got an error: ", err)
	}
}
<|endoftext|>


<commit_before>package autoconfig

import (
	"io/ioutil"
	"os"
	"reflect"
	"testing"

	"github.com/jfbus/autoconfig/ini"
	"github.com/jfbus/autoconfig/yaml"
)

type testCfg struct {
	Key     string `ini:"key" yaml:"key"`
	None    string `ini:"none" yaml:"none"`
	changed int
}

func (t *testCfg) Changed() {
	t.changed++
}

func (t *testCfg) changeCount() int {
	return t.changed
}

type Deeper struct {
	Key string `ini:"key" yaml:"key"`
}

type testDeepCfg struct {
	Deeper  Deeper `yaml:"deeper"`
	None    string `ini:"none" yaml:"none"`
	changed int
}

func (t *testDeepCfg) Changed() {
	t.changed++
}

func (t *testDeepCfg) changeCount() int {
	return t.changed
}

type testClass struct {
	cfg     *testCfg
	changed int
}

func (t *testClass) Reconfigure(c interface{}) {
	t.cfg, _ = c.(*testCfg)

	t.changed++
}

func (t *testClass) changeCount() int {
	return t.changed
}

type changeCounter interface {
	changeCount() int
}

type testLoaderInterface interface {
	loader(string) (Loader, error)
	update(string) error
	clean()
}

type testLoader struct {
	f *os.File
}

func (l *testLoader) write(raw string) error {
	var err error
	l.f, err = ioutil.TempFile("/tmp/", "autoconfig_test_")
	if err != nil {
		return err
	}
	_, err = l.f.WriteString(raw)
	if err != nil {
		return err
	}
	return l.f.Sync()
}

func (l *testLoader) update(raw string) error {
	err := l.f.Truncate(0)
	if err != nil {
		return err
	}
	_, err = l.f.Seek(0, 0)
	if err != nil {
		return err
	}
	_, err = l.f.WriteString(raw)
	if err != nil {
		return err
	}
	return l.f.Close()
}

func (l *testLoader) clean() {
	os.Remove(l.f.Name())
}

type iniLoader struct {
	testLoader
}

func (l *iniLoader) loader(raw string) (Loader, error) {
	err := l.write(raw)
	if err != nil {
		return nil, err
	}
	return ini.New(l.f.Name()), nil
}

type yamlLoader struct {
	testLoader
}

func (l *yamlLoader) loader(raw string) (Loader, error) {
	err := l.write(raw)
	if err != nil {
		return nil, err
	}
	return yaml.New(l.f.Name()), nil
}

type testCase struct {
	name        string
	raw         string
	rawUpdated  string
	loader      testLoaderInterface
	defaults    changeCounter
	afterLoad   changeCounter
	afterUpdate changeCounter
}

var (
	iniRaw = `
[section]
key=foo
`
	iniRawUpdated = `
[section]
key=bar
`

	testCases = []testCase{
		testCase{
			name:        "ini",
			raw:         iniRaw,
			rawUpdated:  iniRawUpdated,
			loader:      &iniLoader{},
			defaults:    &testCfg{None: "foobar"},
			afterLoad:   &testCfg{Key: "foo", None: "foobar", changed: 1},
			afterUpdate: &testCfg{Key: "bar", None: "foobar", changed: 2},
		},
		testCase{
			name: "yaml flat",
			raw: `section:
  key: foo
`,
			rawUpdated: `section:
  key: bar
`,
			loader:      &yamlLoader{},
			defaults:    &testCfg{None: "foobar"},
			afterLoad:   &testCfg{Key: "foo", None: "foobar", changed: 1},
			afterUpdate: &testCfg{Key: "bar", None: "foobar", changed: 2},
		},
		testCase{
			name: "yaml deep",
			raw: `section:
  deeper:
    key: foo
`,
			rawUpdated: `section:
  deeper:
    key: bar
`,
			loader:      &yamlLoader{},
			defaults:    &testDeepCfg{None: "foobar"},
			afterLoad:   &testDeepCfg{Deeper: Deeper{Key: "foo"}, None: "foobar", changed: 1},
			afterUpdate: &testDeepCfg{Deeper: Deeper{Key: "bar"}, None: "foobar", changed: 2},
		},
	}
)

func TestReloadCfg(t *testing.T) {
	for _, tc := range testCases {
		l, err := tc.loader.loader(tc.raw)
		if err != nil {
			t.Fatal("Unable to create config temp file")
		}
		cfg := New(l)
		scfg := tc.defaults
		cfg.Register("section", scfg)
		err = cfg.Load()
		if err != nil {
			t.Errorf("When loading %s conf, Load() returned %s", tc.name, err)
		}
		if !reflect.DeepEqual(scfg, tc.afterLoad) {
			t.Errorf("When loading %s conf, expected <%+v>, got <%+v>", tc.name, tc.afterLoad, scfg)
		}
		tc.loader.update(tc.rawUpdated)
		err = cfg.Reload()
		if err != nil {
			t.Errorf("When loading %s conf, Reload() returned %s", tc.name, err)
		}
		if !reflect.DeepEqual(scfg, tc.afterUpdate) {
			t.Errorf("When reloading %s conf, expected <%+v>, got <%+v>", tc.name, tc.afterUpdate, scfg)
		}
		tc.loader.clean()
	}
}

func TestNoLoader(t *testing.T) {
	err := Load(nil)
	if err != ErrNoLoader {
		t.Errorf("When no loader is defined, Load should return <%s>, got <%s>", ErrNoLoader, err)
	}
}
<commit_msg>better test coverage<commit_after>package autoconfig

import (
	"io/ioutil"
	"os"
	"reflect"
	"testing"

	"github.com/jfbus/autoconfig/ini"
	"github.com/jfbus/autoconfig/yaml"
)

type testCfg struct {
	Key     string `ini:"key" yaml:"key"`
	None    string `ini:"none" yaml:"none"`
	changed int
}

func (t *testCfg) Changed() {
	t.changed++
}

func (t *testCfg) changeCount() int {
	return t.changed
}

type Deeper struct {
	Key string `ini:"key" yaml:"key"`
}

type testDeepCfg struct {
	Deeper  Deeper `yaml:"deeper"`
	None    string `ini:"none" yaml:"none"`
	changed int
}

func (t *testDeepCfg) Changed() {
	t.changed++
}

func (t *testDeepCfg) changeCount() int {
	return t.changed
}

type testClass struct {
	cfg     *testCfg
	changed int
}

func (t *testClass) Reconfigure(c interface{}) {
	t.cfg, _ = c.(*testCfg)

	t.changed++
}

func (t *testClass) changeCount() int {
	return t.changed
}

type changeCounter interface {
	changeCount() int
}

type testLoaderInterface interface {
	loader(string) (Loader, error)
	update(string) error
	clean()
}

type testLoader struct {
	f *os.File
}

func (l *testLoader) write(raw string) error {
	var err error
	l.f, err = ioutil.TempFile("/tmp/", "autoconfig_test_")
	if err != nil {
		return err
	}
	_, err = l.f.WriteString(raw)
	if err != nil {
		return err
	}
	return l.f.Sync()
}

func (l *testLoader) update(raw string) error {
	err := l.f.Truncate(0)
	if err != nil {
		return err
	}
	_, err = l.f.Seek(0, 0)
	if err != nil {
		return err
	}
	_, err = l.f.WriteString(raw)
	if err != nil {
		return err
	}
	return l.f.Close()
}

func (l *testLoader) clean() {
	os.Remove(l.f.Name())
}

type iniLoader struct {
	testLoader
}

func (l *iniLoader) loader(raw string) (Loader, error) {
	err := l.write(raw)
	if err != nil {
		return nil, err
	}
	return ini.New(l.f.Name()), nil
}

type yamlLoader struct {
	testLoader
}

func (l *yamlLoader) loader(raw string) (Loader, error) {
	err := l.write(raw)
	if err != nil {
		return nil, err
	}
	return yaml.New(l.f.Name()), nil
}

type testCase struct {
	name        string
	raw         string
	rawUpdated  string
	loader      testLoaderInterface
	defaults    func() changeCounter
	afterLoad   changeCounter
	afterUpdate changeCounter
}

var (
	iniRaw = `
[section]
key=foo
`
	iniRawUpdated = `
[section]
key=bar
`

	testCases = []testCase{
		testCase{
			name:        "ini",
			raw:         iniRaw,
			rawUpdated:  iniRawUpdated,
			loader:      &iniLoader{},
			defaults:    func() changeCounter { return &testCfg{None: "foobar"} },
			afterLoad:   &testCfg{Key: "foo", None: "foobar", changed: 1},
			afterUpdate: &testCfg{Key: "bar", None: "foobar", changed: 2},
		},
		testCase{
			name: "yaml flat",
			raw: `section:
  key: foo
`,
			rawUpdated: `section:
  key: bar
`,
			loader:      &yamlLoader{},
			defaults:    func() changeCounter { return &testCfg{None: "foobar"} },
			afterLoad:   &testCfg{Key: "foo", None: "foobar", changed: 1},
			afterUpdate: &testCfg{Key: "bar", None: "foobar", changed: 2},
		},
		testCase{
			name: "yaml deep",
			raw: `section:
  deeper:
    key: foo
`,
			rawUpdated: `section:
  deeper:
    key: bar
`,
			loader:      &yamlLoader{},
			defaults:    func() changeCounter { return &testDeepCfg{None: "foobar"} },
			afterLoad:   &testDeepCfg{Deeper: Deeper{Key: "foo"}, None: "foobar", changed: 1},
			afterUpdate: &testDeepCfg{Deeper: Deeper{Key: "bar"}, None: "foobar", changed: 2},
		},
	}
)

func TestReloadCfg(t *testing.T) {
	for _, tc := range testCases {
		l, err := tc.loader.loader(tc.raw)
		if err != nil {
			t.Fatal("Unable to create config temp file")
		}
		cfg := New(l)
		scfg := tc.defaults()
		cfg.Register("section", scfg)
		err = cfg.Load()
		if err != nil {
			t.Errorf("When loading %s conf, Load() returned %s", tc.name, err)
		}
		if !reflect.DeepEqual(scfg, tc.afterLoad) {
			t.Errorf("When loading %s conf, expected <%+v>, got <%+v>", tc.name, tc.afterLoad, scfg)
		}
		tc.loader.update(tc.rawUpdated)
		err = cfg.Reload()
		if err != nil {
			t.Errorf("When loading %s conf, Reload() returned %s", tc.name, err)
		}
		if !reflect.DeepEqual(scfg, tc.afterUpdate) {
			t.Errorf("When reloading %s conf, expected <%+v>, got <%+v>", tc.name, tc.afterUpdate, scfg)
		}
		tc.loader.clean()
	}
}

func TestAfterLoadCfg(t *testing.T) {
	for _, tc := range testCases {
		l, err := tc.loader.loader(tc.raw)
		if err != nil {
			t.Fatal("Unable to create config temp file")
		}
		cfg := New(l)
		scfg := tc.defaults()
		err = cfg.Load()
		if err != nil {
			t.Errorf("When loading %s conf, Load() returned %s", tc.name, err)
		}
		cfg.Register("section", scfg)
		if !reflect.DeepEqual(scfg, tc.afterLoad) {
			t.Errorf("When loading %s conf, expected <%+v>, got <%+v>", tc.name, tc.afterLoad, scfg)
		}
		tc.loader.clean()
	}
}

func TestReloadInstance(t *testing.T) {
	tc := testCases[0]
	l, err := tc.loader.loader(tc.raw)
	if err != nil {
		t.Fatal("Unable to create config temp file")
	}
	cfg := New(l)
	cfg.Register("section", tc.defaults())
	i := &testClass{}
	cfg.Reconfigure("section", i)
	err = cfg.Load()
	if err != nil {
		t.Errorf("When loading %s conf, Load() returned %s", tc.name, err)
	}
	if !reflect.DeepEqual(i.cfg, tc.afterLoad) {
		t.Errorf("When loading %s conf, expected <%+v>, got <%+v>", tc.name, tc.afterLoad, i.cfg)
	}
	tc.loader.update(tc.rawUpdated)
	err = cfg.Reload()
	if err != nil {
		t.Errorf("When loading %s conf, Reload() returned %s", tc.name, err)
	}
	if !reflect.DeepEqual(i.cfg, tc.afterUpdate) {
		t.Errorf("When reloading %s conf, expected <%+v>, got <%+v>", tc.name, tc.afterUpdate, i.cfg)
	}
	tc.loader.clean()
}

func TestAfterLoadInstance(t *testing.T) {
	tc := testCases[0]
	l, err := tc.loader.loader(tc.raw)
	if err != nil {
		t.Fatal("Unable to create config temp file")
	}
	cfg := New(l)
	err = cfg.Load()
	cfg.Register("section", tc.defaults())
	i := &testClass{}
	cfg.Reconfigure("section", i)
	if err != nil {
		t.Errorf("When loading %s conf, Load() returned %s", tc.name, err)
	}
	if !reflect.DeepEqual(i.cfg, tc.afterLoad) {
		t.Errorf("When loading %s conf, expected <%+v>, got <%+v>", tc.name, tc.afterLoad, i.cfg)
	}
	tc.loader.clean()
}

func TestNoLoader(t *testing.T) {
	err := Load(nil)
	if err != ErrNoLoader {
		t.Errorf("When no loader is defined, Load should return <%s>, got <%s>", ErrNoLoader, err)
	}
}
<|endoftext|>


<commit_before>package webhookmodels

type StripePlan struct {
	ID   string `json:"id"`
	Name string `json:"name"`
}

type StripeSubscription struct {
	ID         string     `json:"id"`
	CustomerId string     `json:"customer"`
	Plan       StripePlan `json:"plan"`
}

type StripePeriod struct {
	Start float64 `json:"start"`
	End   float64 `json:"end"`
}

type StripeInvoiceData struct {
	SubscriptionId string       `json:"id"`
	Period         StripePeriod `json:"period"`
	Plan           StripePlan   `json:"plan"`
}

type StripeInvoiceLines struct {
	Data  []StripeInvoiceData `json:"data"`
	Count int                 `json:"count"`
}

type StripeInvoice struct {
	ID         string             `json:"id"`
	CustomerId string             `json:"customer"`
	AmountDue  float64            `json:"amount_due"`
	Currency   string             `json:"currency"`
	Lines      StripeInvoiceLines `json:"lines"`
}

type StripeCard struct {
	Id      string `json:"id"`
	ExpYear string `json:"exp_year"`
	Last4   string `json:"last4"`
	Brand   string `json:"brand"`
}

type StripeCharge struct {
	Card       *StripeCard `json:"card"`
	Currency   string      `json:"currency"`
	Amount     float64     `json:"amount"`
	CustomerId string      `json:"customer"`
}

type StripeCustomer struct {
	ID string `json:"id"`
}
<commit_msg>paymentwebhook: don't unmarshal stripe card in charge webhook req<commit_after>package webhookmodels

type StripePlan struct {
	ID   string `json:"id"`
	Name string `json:"name"`
}

type StripeSubscription struct {
	ID         string     `json:"id"`
	CustomerId string     `json:"customer"`
	Plan       StripePlan `json:"plan"`
}

type StripePeriod struct {
	Start float64 `json:"start"`
	End   float64 `json:"end"`
}

type StripeInvoiceData struct {
	SubscriptionId string       `json:"id"`
	Period         StripePeriod `json:"period"`
	Plan           StripePlan   `json:"plan"`
}

type StripeInvoiceLines struct {
	Data  []StripeInvoiceData `json:"data"`
	Count int                 `json:"count"`
}

type StripeInvoice struct {
	ID         string             `json:"id"`
	CustomerId string             `json:"customer"`
	AmountDue  float64            `json:"amount_due"`
	Currency   string             `json:"currency"`
	Lines      StripeInvoiceLines `json:"lines"`
}

type StripeCard struct {
	Id      string `json:"id"`
	ExpYear string `json:"exp_year"`
	Last4   string `json:"last4"`
	Brand   string `json:"brand"`
}

type StripeCharge struct {
	Currency   string  `json:"currency"`
	Amount     float64 `json:"amount"`
	CustomerId string  `json:"customer"`
}

type StripeCustomer struct {
	ID string `json:"id"`
}
<|endoftext|>


<commit_before>/*
Copyright 2018 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 testing

import (
	"math/rand"
	"testing"

	admissionv1 "k8s.io/api/admission/v1"
	admissionv1beta1 "k8s.io/api/admission/v1beta1"
	admissionregv1 "k8s.io/api/admissionregistration/v1"
	admissionregv1beta1 "k8s.io/api/admissionregistration/v1beta1"
	appsv1 "k8s.io/api/apps/v1"
	appsv1beta1 "k8s.io/api/apps/v1beta1"
	appsv1beta2 "k8s.io/api/apps/v1beta2"
	authenticationv1 "k8s.io/api/authentication/v1"
	authenticationv1beta1 "k8s.io/api/authentication/v1beta1"
	authorizationv1 "k8s.io/api/authorization/v1"
	authorizationv1beta1 "k8s.io/api/authorization/v1beta1"
	autoscalingv1 "k8s.io/api/autoscaling/v1"
	autoscalingv2beta1 "k8s.io/api/autoscaling/v2beta1"
	autoscalingv2beta2 "k8s.io/api/autoscaling/v2beta2"
	batchv1 "k8s.io/api/batch/v1"
	batchv1beta1 "k8s.io/api/batch/v1beta1"
	batchv2alpha1 "k8s.io/api/batch/v2alpha1"
	certificatesv1 "k8s.io/api/certificates/v1"
	certificatesv1beta1 "k8s.io/api/certificates/v1beta1"
	coordinationv1 "k8s.io/api/coordination/v1"
	coordinationv1beta1 "k8s.io/api/coordination/v1beta1"
	corev1 "k8s.io/api/core/v1"
	eventsv1 "k8s.io/api/events/v1"
	eventsv1beta1 "k8s.io/api/events/v1beta1"
	extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
	imagepolicyv1alpha1 "k8s.io/api/imagepolicy/v1alpha1"
	networkingv1 "k8s.io/api/networking/v1"
	networkingv1beta1 "k8s.io/api/networking/v1beta1"
	nodev1alpha1 "k8s.io/api/node/v1alpha1"
	nodev1beta1 "k8s.io/api/node/v1beta1"
	policyv1beta1 "k8s.io/api/policy/v1beta1"
	rbacv1 "k8s.io/api/rbac/v1"
	rbacv1alpha1 "k8s.io/api/rbac/v1alpha1"
	rbacv1beta1 "k8s.io/api/rbac/v1beta1"
	schedulingv1 "k8s.io/api/scheduling/v1"
	schedulingv1alpha1 "k8s.io/api/scheduling/v1alpha1"
	schedulingv1beta1 "k8s.io/api/scheduling/v1beta1"
	settingsv1alpha1 "k8s.io/api/settings/v1alpha1"
	storagev1 "k8s.io/api/storage/v1"
	storagev1alpha1 "k8s.io/api/storage/v1alpha1"
	storagev1beta1 "k8s.io/api/storage/v1beta1"

	"github.com/stretchr/testify/require"
	"k8s.io/apimachinery/pkg/api/apitesting/fuzzer"
	"k8s.io/apimachinery/pkg/api/apitesting/roundtrip"
	genericfuzzer "k8s.io/apimachinery/pkg/apis/meta/fuzzer"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/serializer"
)

var groups = []runtime.SchemeBuilder{
	admissionv1beta1.SchemeBuilder,
	admissionv1.SchemeBuilder,
	admissionregv1beta1.SchemeBuilder,
	admissionregv1.SchemeBuilder,
	appsv1beta1.SchemeBuilder,
	appsv1beta2.SchemeBuilder,
	appsv1.SchemeBuilder,
	authenticationv1beta1.SchemeBuilder,
	authenticationv1.SchemeBuilder,
	authorizationv1beta1.SchemeBuilder,
	authorizationv1.SchemeBuilder,
	autoscalingv1.SchemeBuilder,
	autoscalingv2beta1.SchemeBuilder,
	autoscalingv2beta2.SchemeBuilder,
	batchv2alpha1.SchemeBuilder,
	batchv1beta1.SchemeBuilder,
	batchv1.SchemeBuilder,
	certificatesv1.SchemeBuilder,
	certificatesv1beta1.SchemeBuilder,
	coordinationv1.SchemeBuilder,
	coordinationv1beta1.SchemeBuilder,
	corev1.SchemeBuilder,
	eventsv1.SchemeBuilder,
	eventsv1beta1.SchemeBuilder,
	extensionsv1beta1.SchemeBuilder,
	imagepolicyv1alpha1.SchemeBuilder,
	networkingv1.SchemeBuilder,
	networkingv1beta1.SchemeBuilder,
	nodev1alpha1.SchemeBuilder,
	nodev1beta1.SchemeBuilder,
	policyv1beta1.SchemeBuilder,
	rbacv1alpha1.SchemeBuilder,
	rbacv1beta1.SchemeBuilder,
	rbacv1.SchemeBuilder,
	schedulingv1alpha1.SchemeBuilder,
	schedulingv1beta1.SchemeBuilder,
	schedulingv1.SchemeBuilder,
	settingsv1alpha1.SchemeBuilder,
	storagev1alpha1.SchemeBuilder,
	storagev1beta1.SchemeBuilder,
	storagev1.SchemeBuilder,
}

func TestRoundTripExternalTypes(t *testing.T) {
	scheme := runtime.NewScheme()
	codecs := serializer.NewCodecFactory(scheme)
	for _, builder := range groups {
		require.NoError(t, builder.AddToScheme(scheme))
	}
	seed := rand.Int63()
	// I'm only using the generic fuzzer funcs, but at some point in time we might need to
	// switch to specialized. For now we're happy with the current serialization test.
	fuzzer := fuzzer.FuzzerFor(genericfuzzer.Funcs, rand.NewSource(seed), codecs)

	roundtrip.RoundTripExternalTypes(t, scheme, codecs, fuzzer, nil)
}

func TestCompatibility(t *testing.T) {
	scheme := runtime.NewScheme()
	for _, builder := range groups {
		require.NoError(t, builder.AddToScheme(scheme))
	}
	roundtrip.NewCompatibilityTestOptions(scheme).Complete(t).Run(t)
}
<commit_msg>fix import paths<commit_after>/*
Copyright 2018 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 testing

import (
	"math/rand"
	"testing"

	admissionv1 "k8s.io/api/admission/v1"
	admissionv1beta1 "k8s.io/api/admission/v1beta1"
	admissionregv1 "k8s.io/api/admissionregistration/v1"
	admissionregv1beta1 "k8s.io/api/admissionregistration/v1beta1"
	apiserverinternalv1alpha1 "k8s.io/api/apiserverinternal/v1alpha1"
	appsv1 "k8s.io/api/apps/v1"
	appsv1beta1 "k8s.io/api/apps/v1beta1"
	appsv1beta2 "k8s.io/api/apps/v1beta2"
	authenticationv1 "k8s.io/api/authentication/v1"
	authenticationv1beta1 "k8s.io/api/authentication/v1beta1"
	authorizationv1 "k8s.io/api/authorization/v1"
	authorizationv1beta1 "k8s.io/api/authorization/v1beta1"
	autoscalingv1 "k8s.io/api/autoscaling/v1"
	autoscalingv2beta1 "k8s.io/api/autoscaling/v2beta1"
	autoscalingv2beta2 "k8s.io/api/autoscaling/v2beta2"
	batchv1 "k8s.io/api/batch/v1"
	batchv1beta1 "k8s.io/api/batch/v1beta1"
	batchv2alpha1 "k8s.io/api/batch/v2alpha1"
	certificatesv1 "k8s.io/api/certificates/v1"
	certificatesv1beta1 "k8s.io/api/certificates/v1beta1"
	coordinationv1 "k8s.io/api/coordination/v1"
	coordinationv1beta1 "k8s.io/api/coordination/v1beta1"
	corev1 "k8s.io/api/core/v1"
	eventsv1 "k8s.io/api/events/v1"
	eventsv1beta1 "k8s.io/api/events/v1beta1"
	extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
	imagepolicyv1alpha1 "k8s.io/api/imagepolicy/v1alpha1"
	networkingv1 "k8s.io/api/networking/v1"
	networkingv1beta1 "k8s.io/api/networking/v1beta1"
	nodev1alpha1 "k8s.io/api/node/v1alpha1"
	nodev1beta1 "k8s.io/api/node/v1beta1"
	policyv1beta1 "k8s.io/api/policy/v1beta1"
	rbacv1 "k8s.io/api/rbac/v1"
	rbacv1alpha1 "k8s.io/api/rbac/v1alpha1"
	rbacv1beta1 "k8s.io/api/rbac/v1beta1"
	schedulingv1 "k8s.io/api/scheduling/v1"
	schedulingv1alpha1 "k8s.io/api/scheduling/v1alpha1"
	schedulingv1beta1 "k8s.io/api/scheduling/v1beta1"
	settingsv1alpha1 "k8s.io/api/settings/v1alpha1"
	storagev1 "k8s.io/api/storage/v1"
	storagev1alpha1 "k8s.io/api/storage/v1alpha1"
	storagev1beta1 "k8s.io/api/storage/v1beta1"

	"github.com/stretchr/testify/require"
	"k8s.io/apimachinery/pkg/api/apitesting/fuzzer"
	"k8s.io/apimachinery/pkg/api/apitesting/roundtrip"
	genericfuzzer "k8s.io/apimachinery/pkg/apis/meta/fuzzer"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/serializer"
)

var groups = []runtime.SchemeBuilder{
	admissionv1beta1.SchemeBuilder,
	admissionv1.SchemeBuilder,
	admissionregv1beta1.SchemeBuilder,
	admissionregv1.SchemeBuilder,
	apiserverinternalv1alpha1.SchemeBuilder,
	appsv1beta1.SchemeBuilder,
	appsv1beta2.SchemeBuilder,
	appsv1.SchemeBuilder,
	authenticationv1beta1.SchemeBuilder,
	authenticationv1.SchemeBuilder,
	authorizationv1beta1.SchemeBuilder,
	authorizationv1.SchemeBuilder,
	autoscalingv1.SchemeBuilder,
	autoscalingv2beta1.SchemeBuilder,
	autoscalingv2beta2.SchemeBuilder,
	batchv2alpha1.SchemeBuilder,
	batchv1beta1.SchemeBuilder,
	batchv1.SchemeBuilder,
	certificatesv1.SchemeBuilder,
	certificatesv1beta1.SchemeBuilder,
	coordinationv1.SchemeBuilder,
	coordinationv1beta1.SchemeBuilder,
	corev1.SchemeBuilder,
	eventsv1.SchemeBuilder,
	eventsv1beta1.SchemeBuilder,
	extensionsv1beta1.SchemeBuilder,
	imagepolicyv1alpha1.SchemeBuilder,
	networkingv1.SchemeBuilder,
	networkingv1beta1.SchemeBuilder,
	nodev1alpha1.SchemeBuilder,
	nodev1beta1.SchemeBuilder,
	policyv1beta1.SchemeBuilder,
	rbacv1alpha1.SchemeBuilder,
	rbacv1beta1.SchemeBuilder,
	rbacv1.SchemeBuilder,
	schedulingv1alpha1.SchemeBuilder,
	schedulingv1beta1.SchemeBuilder,
	schedulingv1.SchemeBuilder,
	settingsv1alpha1.SchemeBuilder,
	storagev1alpha1.SchemeBuilder,
	storagev1beta1.SchemeBuilder,
	storagev1.SchemeBuilder,
}

func TestRoundTripExternalTypes(t *testing.T) {
	scheme := runtime.NewScheme()
	codecs := serializer.NewCodecFactory(scheme)
	for _, builder := range groups {
		require.NoError(t, builder.AddToScheme(scheme))
	}
	seed := rand.Int63()
	// I'm only using the generic fuzzer funcs, but at some point in time we might need to
	// switch to specialized. For now we're happy with the current serialization test.
	fuzzer := fuzzer.FuzzerFor(genericfuzzer.Funcs, rand.NewSource(seed), codecs)

	roundtrip.RoundTripExternalTypes(t, scheme, codecs, fuzzer, nil)
}

func TestCompatibility(t *testing.T) {
	scheme := runtime.NewScheme()
	for _, builder := range groups {
		require.NoError(t, builder.AddToScheme(scheme))
	}
	roundtrip.NewCompatibilityTestOptions(scheme).Complete(t).Run(t)
}
<|endoftext|>


<commit_before>package brokerapi

import (
	"context"
	"encoding/json"
	"errors"
	"net/http"
)

type ServiceBroker interface {
	Services(ctx context.Context) []Service

	Provision(ctx context.Context, instanceID string, details ProvisionDetails, asyncAllowed bool) (ProvisionedServiceSpec, error)
	Deprovision(ctx context.Context, instanceID string, details DeprovisionDetails, asyncAllowed bool) (DeprovisionServiceSpec, error)

	Bind(ctx context.Context, instanceID, bindingID string, details BindDetails) (Binding, error)
	Unbind(ctx context.Context, instanceID, bindingID string, details UnbindDetails) error

	Update(ctx context.Context, instanceID string, details UpdateDetails, asyncAllowed bool) (UpdateServiceSpec, error)

	LastOperation(ctx context.Context, instanceID, operationData string) (LastOperation, error)
}

type DetailsWithRawParameters interface {
	GetRawParameters() json.RawMessage
}

func (d ProvisionDetails) GetRawParameters() json.RawMessage {
	return d.RawParameters
}

func (d BindDetails) GetRawParameters() json.RawMessage {
	return d.RawParameters
}

func (d UpdateDetails) GetRawParameters() json.RawMessage {
	return d.RawParameters
}

type ProvisionDetails struct {
	ServiceID        string          `json:"service_id"`
	PlanID           string          `json:"plan_id"`
	OrganizationGUID string          `json:"organization_guid"`
	SpaceGUID        string          `json:"space_guid"`
	RawParameters    json.RawMessage `json:"parameters,omitempty"`
}

type ProvisionedServiceSpec struct {
	IsAsync       bool
	DashboardURL  string
	OperationData string
}

type BindDetails struct {
	AppGUID       string          `json:"app_guid"`
	PlanID        string          `json:"plan_id"`
	ServiceID     string          `json:"service_id"`
	BindResource  *BindResource   `json:"bind_resource,omitempty"`
	RawParameters json.RawMessage `json:"parameters,omitempty"`
}

type BindResource struct {
	AppGuid string `json:"app_guid,omitempty"`
	Route   string `json:"route,omitempty"`
}

type UnbindDetails struct {
	PlanID    string `json:"plan_id"`
	ServiceID string `json:"service_id"`
}

type UpdateServiceSpec struct {
	IsAsync       bool
	OperationData string
}

type DeprovisionServiceSpec struct {
	IsAsync       bool
	OperationData string
}

type DeprovisionDetails struct {
	PlanID    string `json:"plan_id"`
	ServiceID string `json:"service_id"`
}

type UpdateDetails struct {
	ServiceID      string          `json:"service_id"`
	PlanID         string          `json:"plan_id"`
	RawParameters  json.RawMessage `json:"parameters,omitempty"`
	PreviousValues PreviousValues  `json:"previous_values"`
}

type PreviousValues struct {
	PlanID    string `json:"plan_id"`
	ServiceID string `json:"service_id"`
	OrgID     string `json:"organization_id"`
	SpaceID   string `json:"space_id"`
}

type LastOperation struct {
	State       LastOperationState
	Description string
}

type LastOperationState string

const (
	InProgress LastOperationState = "in progress"
	Succeeded  LastOperationState = "succeeded"
	Failed     LastOperationState = "failed"
)

type Binding struct {
	Credentials     interface{}   `json:"credentials"`
	SyslogDrainURL  string        `json:"syslog_drain_url,omitempty"`
	RouteServiceURL string        `json:"route_service_url,omitempty"`
	VolumeMounts    []VolumeMount `json:"volume_mounts,omitempty"`
}

type VolumeMount struct {
	Driver       string       `json:"driver"`
	ContainerDir string       `json:"container_dir"`
	Mode         string       `json:"mode"`
	DeviceType   string       `json:"device_type"`
	Device       SharedDevice `json:"device"`
}

type SharedDevice struct {
	VolumeId    string                 `json:"volume_id"`
	MountConfig map[string]interface{} `json:"mount_config"`
}

const (
	instanceExistsMsg           = "instance already exists"
	instanceDoesntExistMsg      = "instance does not exist"
	serviceLimitReachedMsg      = "instance limit for this service has been reached"
	servicePlanQuotaExceededMsg = "The quota for this service plan has been exceeded. Please contact your Operator for help."
	serviceQuotaExceededMsg     = "The quota for this service has been exceeded. Please contact your Operator for help."
	bindingExistsMsg            = "binding already exists"
	bindingDoesntExistMsg       = "binding does not exist"
	asyncRequiredMsg            = "This service plan requires client support for asynchronous service operations."
	planChangeUnsupportedMsg    = "The requested plan migration cannot be performed"
	rawInvalidParamsMsg         = "The format of the parameters is not valid JSON"
	appGuidMissingMsg           = "app_guid is a required field but was not provided"
)

var (
	ErrInstanceAlreadyExists = NewFailureResponseBuilder(
		errors.New(instanceExistsMsg), http.StatusConflict, instanceAlreadyExistsErrorKey,
	).WithEmptyResponse().Build()

	ErrInstanceDoesNotExist = NewFailureResponseBuilder(
		errors.New(instanceDoesntExistMsg), http.StatusGone, instanceMissingErrorKey,
	).WithEmptyResponse().Build()

	ErrInstanceLimitMet = NewFailureResponse(
		errors.New(serviceLimitReachedMsg), http.StatusInternalServerError, instanceLimitReachedErrorKey,
	)

	ErrBindingAlreadyExists = NewFailureResponse(
		errors.New(bindingExistsMsg), http.StatusConflict, bindingAlreadyExistsErrorKey,
	)

	ErrBindingDoesNotExist = NewFailureResponseBuilder(
		errors.New(bindingDoesntExistMsg), http.StatusGone, bindingMissingErrorKey,
	).WithEmptyResponse().Build()

	ErrAsyncRequired = NewFailureResponseBuilder(
		errors.New(asyncRequiredMsg), http.StatusUnprocessableEntity, asyncRequiredKey,
	).WithErrorKey("AsyncRequired").Build()

	ErrPlanChangeNotSupported = NewFailureResponseBuilder(
		errors.New(planChangeUnsupportedMsg), http.StatusUnprocessableEntity, planChangeNotSupportedKey,
	).WithErrorKey("PlanChangeNotSupported").Build()

	ErrRawParamsInvalid = NewFailureResponse(
		errors.New(rawInvalidParamsMsg), http.StatusUnprocessableEntity, invalidRawParamsKey,
	)

	ErrAppGuidNotProvided = NewFailureResponse(
		errors.New(appGuidMissingMsg), http.StatusUnprocessableEntity, appGuidNotProvidedErrorKey,
	)

	ErrPlanQuotaExceeded    = errors.New(servicePlanQuotaExceededMsg)
	ErrServiceQuotaExceeded = errors.New(serviceQuotaExceededMsg)
)
<commit_msg>BindResource can include credential client ID<commit_after>package brokerapi

import (
	"context"
	"encoding/json"
	"errors"
	"net/http"
)

type ServiceBroker interface {
	Services(ctx context.Context) []Service

	Provision(ctx context.Context, instanceID string, details ProvisionDetails, asyncAllowed bool) (ProvisionedServiceSpec, error)
	Deprovision(ctx context.Context, instanceID string, details DeprovisionDetails, asyncAllowed bool) (DeprovisionServiceSpec, error)

	Bind(ctx context.Context, instanceID, bindingID string, details BindDetails) (Binding, error)
	Unbind(ctx context.Context, instanceID, bindingID string, details UnbindDetails) error

	Update(ctx context.Context, instanceID string, details UpdateDetails, asyncAllowed bool) (UpdateServiceSpec, error)

	LastOperation(ctx context.Context, instanceID, operationData string) (LastOperation, error)
}

type DetailsWithRawParameters interface {
	GetRawParameters() json.RawMessage
}

func (d ProvisionDetails) GetRawParameters() json.RawMessage {
	return d.RawParameters
}

func (d BindDetails) GetRawParameters() json.RawMessage {
	return d.RawParameters
}

func (d UpdateDetails) GetRawParameters() json.RawMessage {
	return d.RawParameters
}

type ProvisionDetails struct {
	ServiceID        string          `json:"service_id"`
	PlanID           string          `json:"plan_id"`
	OrganizationGUID string          `json:"organization_guid"`
	SpaceGUID        string          `json:"space_guid"`
	RawParameters    json.RawMessage `json:"parameters,omitempty"`
}

type ProvisionedServiceSpec struct {
	IsAsync       bool
	DashboardURL  string
	OperationData string
}

type BindDetails struct {
	AppGUID       string          `json:"app_guid"`
	PlanID        string          `json:"plan_id"`
	ServiceID     string          `json:"service_id"`
	BindResource  *BindResource   `json:"bind_resource,omitempty"`
	RawParameters json.RawMessage `json:"parameters,omitempty"`
}

type BindResource struct {
	AppGuid            string `json:"app_guid,omitempty"`
	Route              string `json:"route,omitempty"`
	CredentialClientID string `json:"credential_client_id,omitempty"`
}

type UnbindDetails struct {
	PlanID    string `json:"plan_id"`
	ServiceID string `json:"service_id"`
}

type UpdateServiceSpec struct {
	IsAsync       bool
	OperationData string
}

type DeprovisionServiceSpec struct {
	IsAsync       bool
	OperationData string
}

type DeprovisionDetails struct {
	PlanID    string `json:"plan_id"`
	ServiceID string `json:"service_id"`
}

type UpdateDetails struct {
	ServiceID      string          `json:"service_id"`
	PlanID         string          `json:"plan_id"`
	RawParameters  json.RawMessage `json:"parameters,omitempty"`
	PreviousValues PreviousValues  `json:"previous_values"`
}

type PreviousValues struct {
	PlanID    string `json:"plan_id"`
	ServiceID string `json:"service_id"`
	OrgID     string `json:"organization_id"`
	SpaceID   string `json:"space_id"`
}

type LastOperation struct {
	State       LastOperationState
	Description string
}

type LastOperationState string

const (
	InProgress LastOperationState = "in progress"
	Succeeded  LastOperationState = "succeeded"
	Failed     LastOperationState = "failed"
)

type Binding struct {
	Credentials     interface{}   `json:"credentials"`
	SyslogDrainURL  string        `json:"syslog_drain_url,omitempty"`
	RouteServiceURL string        `json:"route_service_url,omitempty"`
	VolumeMounts    []VolumeMount `json:"volume_mounts,omitempty"`
}

type VolumeMount struct {
	Driver       string       `json:"driver"`
	ContainerDir string       `json:"container_dir"`
	Mode         string       `json:"mode"`
	DeviceType   string       `json:"device_type"`
	Device       SharedDevice `json:"device"`
}

type SharedDevice struct {
	VolumeId    string                 `json:"volume_id"`
	MountConfig map[string]interface{} `json:"mount_config"`
}

const (
	instanceExistsMsg           = "instance already exists"
	instanceDoesntExistMsg      = "instance does not exist"
	serviceLimitReachedMsg      = "instance limit for this service has been reached"
	servicePlanQuotaExceededMsg = "The quota for this service plan has been exceeded. Please contact your Operator for help."
	serviceQuotaExceededMsg     = "The quota for this service has been exceeded. Please contact your Operator for help."
	bindingExistsMsg            = "binding already exists"
	bindingDoesntExistMsg       = "binding does not exist"
	asyncRequiredMsg            = "This service plan requires client support for asynchronous service operations."
	planChangeUnsupportedMsg    = "The requested plan migration cannot be performed"
	rawInvalidParamsMsg         = "The format of the parameters is not valid JSON"
	appGuidMissingMsg           = "app_guid is a required field but was not provided"
)

var (
	ErrInstanceAlreadyExists = NewFailureResponseBuilder(
		errors.New(instanceExistsMsg), http.StatusConflict, instanceAlreadyExistsErrorKey,
	).WithEmptyResponse().Build()

	ErrInstanceDoesNotExist = NewFailureResponseBuilder(
		errors.New(instanceDoesntExistMsg), http.StatusGone, instanceMissingErrorKey,
	).WithEmptyResponse().Build()

	ErrInstanceLimitMet = NewFailureResponse(
		errors.New(serviceLimitReachedMsg), http.StatusInternalServerError, instanceLimitReachedErrorKey,
	)

	ErrBindingAlreadyExists = NewFailureResponse(
		errors.New(bindingExistsMsg), http.StatusConflict, bindingAlreadyExistsErrorKey,
	)

	ErrBindingDoesNotExist = NewFailureResponseBuilder(
		errors.New(bindingDoesntExistMsg), http.StatusGone, bindingMissingErrorKey,
	).WithEmptyResponse().Build()

	ErrAsyncRequired = NewFailureResponseBuilder(
		errors.New(asyncRequiredMsg), http.StatusUnprocessableEntity, asyncRequiredKey,
	).WithErrorKey("AsyncRequired").Build()

	ErrPlanChangeNotSupported = NewFailureResponseBuilder(
		errors.New(planChangeUnsupportedMsg), http.StatusUnprocessableEntity, planChangeNotSupportedKey,
	).WithErrorKey("PlanChangeNotSupported").Build()

	ErrRawParamsInvalid = NewFailureResponse(
		errors.New(rawInvalidParamsMsg), http.StatusUnprocessableEntity, invalidRawParamsKey,
	)

	ErrAppGuidNotProvided = NewFailureResponse(
		errors.New(appGuidMissingMsg), http.StatusUnprocessableEntity, appGuidNotProvidedErrorKey,
	)

	ErrPlanQuotaExceeded    = errors.New(servicePlanQuotaExceededMsg)
	ErrServiceQuotaExceeded = errors.New(serviceQuotaExceededMsg)
)
<|endoftext|>


<commit_before>package main

import (
	"github.com/zenoss/glog"
	"github.com/zenoss/serviced"
	"github.com/zenoss/serviced/dao"
	"github.com/zenoss/serviced/shell"

	"fmt"
	"net"
	"net/http"
	"os"
	"os/exec"
	"os/signal"
	"sort"
	"syscall"
	"time"
)

// Start a service proxy.
func (cli *ServicedCli) CmdProxy(args ...string) error {

	if err := proxyCmd.Parse(args); err != nil {
		return err
	}
	if len(proxyCmd.Args()) != 2 {
		proxyCmd.Usage()
		glog.Flush()
		os.Exit(2)
	}
	config := serviced.MuxConfig{}
	config.TCPMux.Port = proxyOptions.muxport
	config.TCPMux.Enabled = proxyOptions.mux
	config.TCPMux.UseTLS = proxyOptions.tls
	config.ServiceId = proxyCmd.Arg(0)
	config.Command = proxyCmd.Arg(1)

	if config.TCPMux.Enabled {
		go config.TCPMux.ListenAndMux()
	}

	sio := shell.NewProcessForwarderServer(proxyOptions.servicedEndpoint)
	sio.Handle("/", http.FileServer(http.Dir("/serviced/www/")))
	go http.ListenAndServe(":50000", sio)

	procexit := make(chan int)
	sigc := make(chan os.Signal, 1)
	signal.Notify(sigc,
		syscall.SIGINT,
		syscall.SIGTERM,
		syscall.SIGQUIT)

	// continually execute subprocess
	go func(cmdString string) {
		defer func() { procexit <- 0 }()
		for {
			glog.V(0).Info("About to execute: ", cmdString)
			cmd := exec.Command("bash", "-c", cmdString)
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stderr
			cmd.Stdin = os.Stdin
			serviceExit := make(chan error)
			go func() {
				serviceExit <- cmd.Run()
			}()
			select {
			case sig := <-sigc:
				glog.V(1).Infof("Caught signal %d", sig)
				cmd.Process.Signal(sig)
				cmd.Wait()
				exitCode := 0
				if cmd.ProcessState != nil {
					exitCode, _ = cmd.ProcessState.Sys().(int)
				}
				procexit <- exitCode
			case cmderr := <-serviceExit:
				if cmderr != nil {
					client, err := serviced.NewLBClient(proxyOptions.servicedEndpoint)
					message := fmt.Sprintf("Problem running service: %v. Command \"%v\" failed: %v", config.ServiceId, config.Command, err)
					if err == nil {
						defer client.Close()
						glog.Errorf(message)

						// send the log message to the master
						client.SendLogMessage(serviced.ServiceLogInfo{config.ServiceId, message}, nil)
					} else {
						glog.Errorf("Failed to create a client to endpoint %s: %s", proxyOptions.servicedEndpoint, err)
					}

					glog.Infof("%s", err)
					glog.Flush()
					if exiterr, ok := cmderr.(*exec.ExitError); ok && !proxyOptions.autorestart {
						if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
							procexit <- status.ExitStatus()
						}
					}
				}
			}

			if !proxyOptions.autorestart {
				break
			}
			glog.V(0).Info("service exited, sleeping...")
			time.Sleep(time.Minute)
		}
	}(config.Command)

	if proxyOptions.logstash {
		go func() {
			// make sure we pick up any logfile that was modified within the
			// last three years
			// TODO: Either expose the 3 years a configurable or get rid of it
			cmdString := serviced.LOGSTASH_CONTAINER_DIRECTORY + "/logstash-forwarder " + " -old-files-hours=26280 -config " + serviced.LOGSTASH_CONTAINER_CONFIG
			glog.V(0).Info("About to execute: ", cmdString)
			myCmd := exec.Command("bash", "-c", cmdString)
			myCmd.Stdout = os.Stdout
			myCmd.Stderr = os.Stderr
			myErr := myCmd.Run()
			if myErr != nil {
				glog.Errorf("Problem running service: %v", myErr)
				glog.Flush()
			}
		}()
	}

	//monitor application endpoints to mux ports
	go func() {
		for {
			func() {
				client, err := serviced.NewLBClient(proxyOptions.servicedEndpoint)
				if err != nil {
					glog.Errorf("Could not create a client to endpoint %s: %s", proxyOptions.servicedEndpoint, err)
					return
				}
				defer client.Close()

				var endpoints map[string][]*dao.ApplicationEndpoint
				err = client.GetServiceEndpoints(config.ServiceId, &endpoints)
				if err != nil {
					glog.Errorf("Error getting application endpoints for service %s: %s", config.ServiceId, err)
					return
				}

				for key, endpointList := range endpoints {
					if len(endpointList) <= 0 {
						glog.Warningf("No endpoints found for %s", key)
						if proxy, ok := proxies[key]; ok {
							emptyAddressList := make([]string, 0)
							proxy.SetNewAddresses(emptyAddressList)
						}
						continue
					}

					addresses := make([]string, len(endpointList))
					for i, endpoint := range endpointList {
						addresses[i] = fmt.Sprintf("%s:%d", endpoint.HostIp, endpoint.HostPort)
					}
					sort.Strings(addresses)

					var proxy *serviced.Proxy
					var ok bool
					if proxy, ok = proxies[key]; !ok {
						glog.Infof("Attempting port map for: %s -> %+v", key, *endpointList[0])

						// setup a new proxy
						listener, err := net.Listen("tcp4", fmt.Sprintf(":%d", endpointList[0].ContainerPort))
						if err != nil {
							glog.Errorf("Could not bind to port: %s", err)
							continue
						}
						proxy, err = serviced.NewProxy(
							fmt.Sprintf("%v", endpointList[0]),
							uint16(config.TCPMux.Port),
							config.TCPMux.UseTLS,
							listener)
						if err != nil {
							glog.Errorf("Could not build proxy %s", err)
							continue
						}

						glog.Infof("Success binding port: %s -> %+v", key, proxy)
						proxies[key] = proxy
					}
					proxy.SetNewAddresses(addresses)
				}
			}()

			time.Sleep(time.Second * 10)
		}
	}()

	//setup container metric forwarder
	go func() {
		//loop until successfully identifying this container's tenant id
		var tenantId string
		for {
			client, err := serviced.NewLBClient(proxyOptions.servicedEndpoint)
			if err == nil {
				defer client.Close()
				if err = client.GetTenantId(config.ServiceId, &tenantId); err != nil {
					glog.Errorf("Failed to get tenant id: %s", err)
				} else {
					//success
					break
				}
			} else {
				glog.Errorf("Failed to create a client to endpoint %s: %s", proxyOptions.servicedEndpoint, err)
			}
		}

		//build metric redirect url -- assumes 8444 is port mapped
		metric_redirect := "http://localhost:8444/api/metrics/store"
		metric_redirect += "?controlplane_tenant_id=" + tenantId
		metric_redirect += "&controlplane_service_id=" + config.ServiceId

		//build and serve the container metric forwarder
		forwarder, _ := serviced.NewMetricForwarder(":22350", metric_redirect)
		forwarder.Serve()
	}()

	exitcode := <-procexit // Wait for proc goroutine to exit

	glog.Flush()
	os.Exit(exitcode)
	return nil
}

var proxies map[string]*serviced.Proxy

func init() {
	proxies = make(map[string]*serviced.Proxy)
}
<commit_msg>Updated proxy message to seem less threatening<commit_after>package main

import (
	"github.com/zenoss/glog"
	"github.com/zenoss/serviced"
	"github.com/zenoss/serviced/dao"
	"github.com/zenoss/serviced/shell"

	"fmt"
	"net"
	"net/http"
	"os"
	"os/exec"
	"os/signal"
	"sort"
	"syscall"
	"time"
)

// Start a service proxy.
func (cli *ServicedCli) CmdProxy(args ...string) error {

	if err := proxyCmd.Parse(args); err != nil {
		return err
	}
	if len(proxyCmd.Args()) != 2 {
		proxyCmd.Usage()
		glog.Flush()
		os.Exit(2)
	}
	config := serviced.MuxConfig{}
	config.TCPMux.Port = proxyOptions.muxport
	config.TCPMux.Enabled = proxyOptions.mux
	config.TCPMux.UseTLS = proxyOptions.tls
	config.ServiceId = proxyCmd.Arg(0)
	config.Command = proxyCmd.Arg(1)

	if config.TCPMux.Enabled {
		go config.TCPMux.ListenAndMux()
	}

	sio := shell.NewProcessForwarderServer(proxyOptions.servicedEndpoint)
	sio.Handle("/", http.FileServer(http.Dir("/serviced/www/")))
	go http.ListenAndServe(":50000", sio)

	procexit := make(chan int)
	sigc := make(chan os.Signal, 1)
	signal.Notify(sigc,
		syscall.SIGINT,
		syscall.SIGTERM,
		syscall.SIGQUIT)

	// continually execute subprocess
	go func(cmdString string) {
		defer func() { procexit <- 0 }()
		for {
			glog.V(0).Info("About to execute: ", cmdString)
			cmd := exec.Command("bash", "-c", cmdString)
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stderr
			cmd.Stdin = os.Stdin
			serviceExit := make(chan error)
			go func() {
				serviceExit <- cmd.Run()
			}()
			select {
			case sig := <-sigc:
				glog.V(1).Infof("Caught signal %d", sig)
				cmd.Process.Signal(sig)
				cmd.Wait()
				exitCode := 0
				if cmd.ProcessState != nil {
					exitCode, _ = cmd.ProcessState.Sys().(int)
				}
				procexit <- exitCode
			case cmderr := <-serviceExit:
				if cmderr != nil {
					client, err := serviced.NewLBClient(proxyOptions.servicedEndpoint)
					message := fmt.Sprintf("Service returned a non-zero exit code: %v. Command: \"%v\" Message: %v", config.ServiceId, config.Command, err)
					if err == nil {
						defer client.Close()
						glog.Errorf(message)

						// send the log message to the master
						client.SendLogMessage(serviced.ServiceLogInfo{config.ServiceId, message}, nil)
					} else {
						glog.Errorf("Failed to create a client to endpoint %s: %s", proxyOptions.servicedEndpoint, err)
					}

					glog.Infof("%s", err)
					glog.Flush()
					if exiterr, ok := cmderr.(*exec.ExitError); ok && !proxyOptions.autorestart {
						if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
							procexit <- status.ExitStatus()
						}
					}
				}
			}

			if !proxyOptions.autorestart {
				break
			}
			glog.V(0).Info("service exited, sleeping...")
			time.Sleep(time.Minute)
		}
	}(config.Command)

	if proxyOptions.logstash {
		go func() {
			// make sure we pick up any logfile that was modified within the
			// last three years
			// TODO: Either expose the 3 years a configurable or get rid of it
			cmdString := serviced.LOGSTASH_CONTAINER_DIRECTORY + "/logstash-forwarder " + " -old-files-hours=26280 -config " + serviced.LOGSTASH_CONTAINER_CONFIG
			glog.V(0).Info("About to execute: ", cmdString)
			myCmd := exec.Command("bash", "-c", cmdString)
			myCmd.Stdout = os.Stdout
			myCmd.Stderr = os.Stderr
			myErr := myCmd.Run()
			if myErr != nil {
				glog.Errorf("Problem running service: %v", myErr)
				glog.Flush()
			}
		}()
	}

	//monitor application endpoints to mux ports
	go func() {
		for {
			func() {
				client, err := serviced.NewLBClient(proxyOptions.servicedEndpoint)
				if err != nil {
					glog.Errorf("Could not create a client to endpoint %s: %s", proxyOptions.servicedEndpoint, err)
					return
				}
				defer client.Close()

				var endpoints map[string][]*dao.ApplicationEndpoint
				err = client.GetServiceEndpoints(config.ServiceId, &endpoints)
				if err != nil {
					glog.Errorf("Error getting application endpoints for service %s: %s", config.ServiceId, err)
					return
				}

				for key, endpointList := range endpoints {
					if len(endpointList) <= 0 {
						glog.Warningf("No endpoints found for %s", key)
						if proxy, ok := proxies[key]; ok {
							emptyAddressList := make([]string, 0)
							proxy.SetNewAddresses(emptyAddressList)
						}
						continue
					}

					addresses := make([]string, len(endpointList))
					for i, endpoint := range endpointList {
						addresses[i] = fmt.Sprintf("%s:%d", endpoint.HostIp, endpoint.HostPort)
					}
					sort.Strings(addresses)

					var proxy *serviced.Proxy
					var ok bool
					if proxy, ok = proxies[key]; !ok {
						glog.Infof("Attempting port map for: %s -> %+v", key, *endpointList[0])

						// setup a new proxy
						listener, err := net.Listen("tcp4", fmt.Sprintf(":%d", endpointList[0].ContainerPort))
						if err != nil {
							glog.Errorf("Could not bind to port: %s", err)
							continue
						}
						proxy, err = serviced.NewProxy(
							fmt.Sprintf("%v", endpointList[0]),
							uint16(config.TCPMux.Port),
							config.TCPMux.UseTLS,
							listener)
						if err != nil {
							glog.Errorf("Could not build proxy %s", err)
							continue
						}

						glog.Infof("Success binding port: %s -> %+v", key, proxy)
						proxies[key] = proxy
					}
					proxy.SetNewAddresses(addresses)
				}
			}()

			time.Sleep(time.Second * 10)
		}
	}()

	//setup container metric forwarder
	go func() {
		//loop until successfully identifying this container's tenant id
		var tenantId string
		for {
			client, err := serviced.NewLBClient(proxyOptions.servicedEndpoint)
			if err == nil {
				defer client.Close()
				if err = client.GetTenantId(config.ServiceId, &tenantId); err != nil {
					glog.Errorf("Failed to get tenant id: %s", err)
				} else {
					//success
					break
				}
			} else {
				glog.Errorf("Failed to create a client to endpoint %s: %s", proxyOptions.servicedEndpoint, err)
			}
		}

		//build metric redirect url -- assumes 8444 is port mapped
		metric_redirect := "http://localhost:8444/api/metrics/store"
		metric_redirect += "?controlplane_tenant_id=" + tenantId
		metric_redirect += "&controlplane_service_id=" + config.ServiceId

		//build and serve the container metric forwarder
		forwarder, _ := serviced.NewMetricForwarder(":22350", metric_redirect)
		forwarder.Serve()
	}()

	exitcode := <-procexit // Wait for proc goroutine to exit

	glog.Flush()
	os.Exit(exitcode)
	return nil
}

var proxies map[string]*serviced.Proxy

func init() {
	proxies = make(map[string]*serviced.Proxy)
}
<|endoftext|>


<commit_before>//go:generate go run maketables.go > tables.go

package confusables

import (
	"unicode/utf8"

	"code.google.com/p/go.text/unicode/norm"
)

// TODO: document casefolding approaches
// (suggest to force casefold strings; explain how to catch paypal - pAypal)
// TODO: implement tables other than MA
// (is it secure, even if overprocessing, to check only against MA?)
// TODO: DOC you might want to store the Skeleton and check against it later
// TODO: implement xidmodifications.txt restricted characters

// Skeleton converts a string to it's "skeleton" form
// as descibed in http://www.unicode.org/reports/tr39/#Confusable_Detection
func Skeleton(s string) string {

	// 1. Converting X to NFD format
	s = norm.NFD.String(s)

	// 2. Successively mapping each source character in X to the target string
	// according to the specified data table
	for i, w := 0, 0; i < len(s); i += w {
		char, width := utf8.DecodeRuneInString(s[i:])
		replacement, exists := confusablesMap[char]
		if exists {
			s = s[:i] + replacement + s[i+width:]
			w = len(replacement)
		} else {
			w = width
		}
	}

	// 3. Reapplying NFD
	s = norm.NFD.String(s)

	return s
}

func Confusable(x, y string) bool {
	return Skeleton(x) == Skeleton(y)
}
<commit_msg>Update norm package location<commit_after>//go:generate go run maketables.go > tables.go

package confusables

import (
	"unicode/utf8"

	"golang.org/x/text/unicode/norm"
)

// TODO: document casefolding approaches
// (suggest to force casefold strings; explain how to catch paypal - pAypal)
// TODO: implement tables other than MA
// (is it secure, even if overprocessing, to check only against MA?)
// TODO: DOC you might want to store the Skeleton and check against it later
// TODO: implement xidmodifications.txt restricted characters

// Skeleton converts a string to it's "skeleton" form
// as descibed in http://www.unicode.org/reports/tr39/#Confusable_Detection
func Skeleton(s string) string {

	// 1. Converting X to NFD format
	s = norm.NFD.String(s)

	// 2. Successively mapping each source character in X to the target string
	// according to the specified data table
	for i, w := 0, 0; i < len(s); i += w {
		char, width := utf8.DecodeRuneInString(s[i:])
		replacement, exists := confusablesMap[char]
		if exists {
			s = s[:i] + replacement + s[i+width:]
			w = len(replacement)
		} else {
			w = width
		}
	}

	// 3. Reapplying NFD
	s = norm.NFD.String(s)

	return s
}

func Confusable(x, y string) bool {
	return Skeleton(x) == Skeleton(y)
}
<|endoftext|>


<commit_before>package models

import (
	"database/sql"
	//"github.com/Zamiell/isaac-racing-server/src/log"

	"github.com/go-sql-driver/mysql"
)

/*
	These are functions used for the listing the schedules for tournaments
	on the website
*/

// TournamentRace holds data for a single race
type TournamentRace struct {
	TournamentName  sql.NullString
	TournamentID    sql.NullString
	TournamentType  sql.NullString
	RaceID          sql.NullInt64
	Racer1          sql.NullString
	Racer2          sql.NullString
	RaceState       sql.NullString
	TournamentRound sql.NullInt64
	RaceDateTime    mysql.NullTime
	ChallongeID     sql.NullInt64
	RaceCaster      sql.NullString
}

// GetTournamentRaces gets all data for all races
func (*Tournament) GetTournamentRaces() ([]TournamentRace, error) {
	var rows *sql.Rows
	if v, err := db.Query(`
		SELECT
				tr.tournament_name,
				tr.challonge_url,
				tr.id,
				trs1.username,
				trs2.username,
				tr.state,
				tr.bracket_round,
				tr.datetime_scheduled,
				tr.challonge_match_id,
				c.username
		FROM
			isaac.tournament_races tr
					LEFT JOIN
							isaac.tournament_racers trs1 ON trs1.id = tr.racer1
					LEFT JOIN
							isaac.tournament_racers trs2 ON trs2.id = tr.racer2
					LEFT JOIN
							isaac.tournament_racers c ON c.id = tr.caster
		WHERE
				tr.state in ('scheduled', 'inProgress')
		ORDER BY datetime_scheduled ASC
	`); err != nil {
		return nil, err
	} else {
		rows = v
	}
	defer rows.Close()

	tournamentRaces := make([]TournamentRace, 0)
	for rows.Next() {
		var race TournamentRace
		if err := rows.Scan(
			&race.TournamentName,
			&race.TournamentID,
			&race.RaceID,
			&race.Racer1,
			&race.Racer2,
			&race.RaceState,
			&race.TournamentRound,
			&race.RaceDateTime,
			&race.ChallongeID,
			&race.RaceCaster,
		); err == sql.ErrNoRows {
			return nil, sql.ErrNoRows
		} else if err != nil {
			return nil, err
		}
		tournamentRaces = append(tournamentRaces, race)
	}
	if len(tournamentRaces) == 0 {
		return nil, sql.ErrNoRows
	}
	return tournamentRaces, nil
}
<commit_msg>Excluding instead of including<commit_after>package models

import (
	"database/sql"
	//"github.com/Zamiell/isaac-racing-server/src/log"

	"github.com/go-sql-driver/mysql"
)

/*
	These are functions used for the listing the schedules for tournaments
	on the website
*/

// TournamentRace holds data for a single race
type TournamentRace struct {
	TournamentName  sql.NullString
	TournamentID    sql.NullString
	TournamentType  sql.NullString
	RaceID          sql.NullInt64
	Racer1          sql.NullString
	Racer2          sql.NullString
	RaceState       sql.NullString
	TournamentRound sql.NullInt64
	RaceDateTime    mysql.NullTime
	ChallongeID     sql.NullInt64
	RaceCaster      sql.NullString
}

// GetTournamentRaces gets all data for all races
func (*Tournament) GetTournamentRaces() ([]TournamentRace, error) {
	var rows *sql.Rows
	if v, err := db.Query(`
		SELECT
				tr.tournament_name,
				tr.challonge_url,
				tr.id,
				trs1.username,
				trs2.username,
				tr.state,
				tr.bracket_round,
				tr.datetime_scheduled,
				tr.challonge_match_id,
				c.username
		FROM
			isaac.tournament_races tr
					LEFT JOIN
							isaac.tournament_racers trs1 ON trs1.id = tr.racer1
					LEFT JOIN
							isaac.tournament_racers trs2 ON trs2.id = tr.racer2
					LEFT JOIN
							isaac.tournament_racers c ON c.id = tr.caster
		WHERE
				tr.state not in ('initial', 'completed')
		ORDER BY datetime_scheduled ASC
	`); err != nil {
		return nil, err
	} else {
		rows = v
	}
	defer rows.Close()

	tournamentRaces := make([]TournamentRace, 0)
	for rows.Next() {
		var race TournamentRace
		if err := rows.Scan(
			&race.TournamentName,
			&race.TournamentID,
			&race.RaceID,
			&race.Racer1,
			&race.Racer2,
			&race.RaceState,
			&race.TournamentRound,
			&race.RaceDateTime,
			&race.ChallongeID,
			&race.RaceCaster,
		); err == sql.ErrNoRows {
			return nil, sql.ErrNoRows
		} else if err != nil {
			return nil, err
		}
		tournamentRaces = append(tournamentRaces, race)
	}
	if len(tournamentRaces) == 0 {
		return nil, sql.ErrNoRows
	}
	return tournamentRaces, nil
}
<|endoftext|>


<commit_before>package service

import (
	"database/sql"
	"fmt"

	"code.google.com/p/go.crypto/bcrypt"
	"github.com/cybersiddhu/go-micro-auth/api"
	"gopkg.in/dgrijalva/jwt-go.v2"
	"gopkg.in/gin-gonic/gin.v0"
	"gopkg.in/jmoiron/sqlx.v0"
)

const (
	userCheckStmt = `
	SELECT users.* FROM users where email = ?
	`
	userInsertStmt = `
	INSERT INTO users(email, password) VALUES(?, ?)
	`
)

type AuthResource struct {
	Dbh    *sqlx.DB
	PrvKey []byte
}

func (ar *AuthResource) CreateSession(c *gin.Context) {
	var ju api.UserJSON
	// validate input by binding to an expected json structure
	if !c.Bind(&ju) {
		c.JSON(400, gin.H{"message": "malformed json"})
	}

	// check if the email matches
	u := api.UserJSON{}
	err := ar.Dbh.Get(&u, userCheckStmt, ju.Email)
	if err != nil {
		if err == sql.ErrNoRows {
			c.JSON(400, gin.H{"message": fmt.Sprintf("email %s not found", ju.Email)})
		} else {
			c.JSON(401, gin.H{"message": err})
		}
	}

	// check if password matches
	err = bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(ju.Password))
	if err != nil {
		c.JSON(401, gin.H{"message": "password do not match"})
	}

	// generate a json web token
	token := jwt.New(jwt.GetSigningMethod("HS256"))
	token.Claims["user_id"] = u.Id
	token.Claims["email"] = u.Email
	tokenString, err := token.SignedString(ar.PrvKey)
	if err != nil {
		c.JSON(400, gin.H{"message": err})
	}
	// successful response
	c.JSON(201, gin.H{"token": tokenString})
}

func (ar *AuthResource) CreateUser(c *gin.Context) {
	var ju api.UserJSON
	// validate input by binding to an expected json structure
	if !c.Bind(&ju) {
		c.JSON(400, gin.H{"message": "malformed json"})
	}
	epass, err := bcrypt.GenerateFromPassword([]byte(ju.Password), bcrypt.DefaultCost)
	if err != nil {
		c.JSON(400, gin.H{"message": err})
	}
	_, err = ar.Dbh.Exec(userInsertStmt, ju.Email, epass)
	if err != nil {
		c.JSON(400, gin.H{"message": err})
	}
	c.JSON(200, gin.H{"message": fmt.Sprintf("user with email %s created", ju.Email)})
}
<commit_msg>Added return statement to get back the correct response Use sprintf to return the stringify version of errors<commit_after>package service

import (
	"database/sql"
	"fmt"

	"code.google.com/p/go.crypto/bcrypt"
	"github.com/cybersiddhu/go-micro-auth/api"
	"gopkg.in/dgrijalva/jwt-go.v2"
	"gopkg.in/gin-gonic/gin.v0"
	"gopkg.in/jmoiron/sqlx.v0"
)

const (
	userCheckStmt = `
	SELECT users.email, users.password FROM users where email = ?
	`
	userInsertStmt = `
	INSERT INTO users(email, password) VALUES(?, ?)
	`
)

type AuthResource struct {
	Dbh    *sqlx.DB
	PrvKey []byte
}

func (ar *AuthResource) CreateSession(c *gin.Context) {
	var ju api.UserJSON
	// validate input by binding to an expected json structure
	if !c.Bind(&ju) {
		c.JSON(400, gin.H{"message": "malformed json"})
		return
	}

	// check if the email matches
	u := api.UserJSON{}
	err := ar.Dbh.Get(&u, userCheckStmt, ju.Email)
	if err != nil {
		if err == sql.ErrNoRows {
			c.JSON(400, gin.H{"message": fmt.Sprintf("email %s not found", ju.Email)})
		} else {
			c.JSON(401, gin.H{"message": fmt.Sprintf("database errors %s", err)})
		}
		return
	}

	// check if password matches
	err = bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(ju.Password))
	if err != nil {
		c.JSON(401, gin.H{"message": "password do not match"})
		return
	}

	// generate a json web token
	token := jwt.New(jwt.GetSigningMethod("HS256"))
	token.Claims["user_id"] = u.Id
	token.Claims["email"] = u.Email
	tokenString, err := token.SignedString(ar.PrvKey)
	if err != nil {
		c.JSON(400, gin.H{"message": err})
		return
	}
	// successful response
	c.JSON(201, gin.H{"token": tokenString})
}

func (ar *AuthResource) CreateUser(c *gin.Context) {
	var ju api.UserJSON
	// validate input by binding to an expected json structure
	if !c.Bind(&ju) {
		c.JSON(400, gin.H{"message": "malformed json"})
		return
	}
	epass, err := bcrypt.GenerateFromPassword([]byte(ju.Password), bcrypt.DefaultCost)
	if err != nil {
		c.JSON(400, gin.H{"message": fmt.Sprint(err)})
		return
	}
	_, err = ar.Dbh.Exec(userInsertStmt, ju.Email, epass)
	if err != nil {
		c.JSON(400, gin.H{"message": fmt.Sprint(err)})
		return
	}
	c.JSON(200, gin.H{"message": fmt.Sprintf("user with email %s created", ju.Email)})
}
<|endoftext|>


<commit_before>package spec

// LayerService provides business logic to manage connections inside network
// layers. There are three different kinds of layer service implementations in
// use. Each implementation takes care about connections between peers within
// the layer of its own responsibility. Connections across layers can be managed
// using the plain usage of the connection service (see ConnectionService).
//
//     behaviour
//
//         The behaviour layer service manages connections of the behaviour
//         layer of the connection space. Subject of this layer are connections
//         between behaviours. Note that behaviour is implemented in form of CLG
//         services (see CLGService).
//
//     information
//
//         The information layer service manages connections of the information
//         layer of the connection space. Subject of this layer are connections
//         between information. Note that information are provided in form of
//         input, which is received via input services (see InputService).
//
//     position
//
//         The position layer service manages connections of the position layer
//         of the connection space. Subject of this layer are connections
//         between positions. Note that positions are managed implicitely, which
//         means that the position layer service is used by the behaviour and
//         information layer services. Positions of peers need to be managed for
//         all kinds of peers within the connection space.
//
type LayerService interface {
	Boot()
	CreateConnection(peerA, peerB string) error
	DeleteConnection(peerA, peerB string) error
	Metadata() map[string]string
	Service() ServiceCollection
	SetServiceCollection(serviceCollection ServiceCollection)
}
<commit_msg>added SetKind method to layer service (#15)<commit_after>package spec

// LayerService provides business logic to manage connections inside network
// layers. There are three different kinds of layer service implementations in
// use. Each implementation takes care about connections between peers within
// the layer of its own responsibility. Connections across layers can be managed
// using the plain usage of the connection service (see ConnectionService).
//
//     behaviour
//
//         The behaviour layer service manages connections of the behaviour
//         layer of the connection space. Subject of this layer are connections
//         between behaviours. Note that behaviour is implemented in form of CLG
//         services (see CLGService).
//
//     information
//
//         The information layer service manages connections of the information
//         layer of the connection space. Subject of this layer are connections
//         between information. Note that information are provided in form of
//         input, which is received via input services (see InputService).
//
//     position
//
//         The position layer service manages connections of the position layer
//         of the connection space. Subject of this layer are connections
//         between positions. Note that positions are managed implicitely, which
//         means that the position layer service is used by the behaviour and
//         information layer services. Positions of peers need to be managed for
//         all kinds of peers within the connection space.
//
type LayerService interface {
	Boot()
	CreateConnection(peerA, peerB string) error
	DeleteConnection(peerA, peerB string) error
	Metadata() map[string]string
	Service() ServiceCollection
	SetKind(kind string)
	SetServiceCollection(serviceCollection ServiceCollection)
}
<|endoftext|>


<commit_before>package collectors

import (
	"fmt"
	"strconv"
	"strings"

	"bosun.org/_third_party/golang.org/x/sys/unix"
	"bosun.org/metadata"
	"bosun.org/opentsdb"
)

func init() {
	collectors = append(collectors, &IntervalCollector{F: c_procstats_linux})
}

var CPU_FIELDS = []string{
	"user",
	"nice",
	"system",
	"idle",
	"iowait",
	"irq",
	"softirq",
	"steal",
	"guest",
	"guest_nice",
}

func c_procstats_linux() (opentsdb.MultiDataPoint, error) {
	var md opentsdb.MultiDataPoint
	var Error error
	var sys unix.Sysinfo_t

	unix.Sysinfo(&sys)

	Add(&md, "linux.uptime_total", sys.Uptime, nil, metadata.Gauge, metadata.Second, osSystemUptimeDesc)
	Add(&md, osSystemUptime, sys.Uptime, nil, metadata.Gauge, metadata.Second, osSystemUptimeDesc)
	if err := readLine("/proc/meminfo", func(s string) error {
		s = strings.TrimSuffix(s, " kB")
		m := strings.Split(s, ":")
		if m == nil {
			return nil
		}
		m[1] = strings.TrimSpace(m[1])
		Add(&md, "linux.mem."+strings.ToLower(m[0]), m[1], nil, metadata.Gauge, metadata.KBytes, "")
		return nil
	}); err != nil {
		Error = err
	}
	Add(&md, osMemTotal, sys.Totalram*uint64(sys.Unit), nil, metadata.Gauge, metadata.Bytes, osMemTotalDesc)
	Add(&md, osMemFree, sys.Freeram*uint64(sys.Unit), nil, metadata.Gauge, metadata.Bytes, osMemFreeDesc)
	Add(&md, osMemUsed, (sys.Totalram-sys.Freeram)*uint64(sys.Unit), nil, metadata.Gauge, metadata.Bytes, osMemUsedDesc)
	Add(&md, "linux.loadavg.1_min", sys.Loads[0], nil, metadata.Gauge, metadata.Load, "")
	Add(&md, "linux.loadavg.5_min", sys.Loads[1], nil, metadata.Gauge, metadata.Load, "")
	Add(&md, "linux.loadavg.15_min", sys.Loads[2], nil, metadata.Gauge, metadata.Load, "")
	Add(&md, "linux.loadavg.total_threads", sys.Procs, nil, metadata.Gauge, metadata.Process, "")
	if sys.Totalram != 0 {
		Add(&md, osMemPctFree, (sys.Freeram)/(sys.Totalram)*100, nil, metadata.Gauge, metadata.Pct, osMemFreeDesc)
	}
	if err := readLine("/proc/vmstat", func(s string) error {
		m := strings.Split(s, " ")
		if m == nil {
			return nil
		}
		switch m[0] {
		case "pgpgin", "pgpgout", "pswpin", "pswpout":
			switch {
			case strings.HasSuffix(m[0], "in"):
				Add(&md, "linux.mem."+strings.TrimSuffix(m[0], "in"), m[1], opentsdb.TagSet{"direction": "in"}, metadata.Counter, metadata.Page, "")
			case strings.HasSuffix(m[0], "out"):
				Add(&md, "linux.mem."+strings.TrimSuffix(m[0], "out"), m[1], opentsdb.TagSet{"direction": "out"}, metadata.Counter, metadata.Page, "")
			}
		case "pgfault", "pgmajfault":
			Add(&md, "linux.mem."+m[0], m[1], nil, metadata.Counter, metadata.Page, "")
		default:
			Add(&md, "linux.mem."+m[0], m[1], nil, metadata.Counter, metadata.None, "")
		}
		return nil
	}); err != nil {
		Error = err
	}
	num_cores := 0
	var t_util int
	cpu_stat_desc := map[string]string{
		"user":       "Normal processes executing in user mode.",
		"nice":       "Niced processes executing in user mode.",
		"system":     "Processes executing in kernel mode.",
		"idle":       "Twiddling thumbs.",
		"iowait":     "Waiting for I/O to complete.",
		"irq":        "Servicing interrupts.",
		"softirq":    "Servicing soft irqs.",
		"steal":      "Involuntary wait.",
		"guest":      "Running a guest vm.",
		"guest_nice": "Running a niced guest vm.",
	}
	if err := readLine("/proc/stat", func(s string) error {
		m := strings.Split(s, " ")
		if m == nil {
			return nil
		}
		switch {
		case strings.HasPrefix(m[0], "cpu"):
			tag_cpu := strings.TrimPrefix(m[0], "cpu")
			if tag_cpu != "" {
				num_cores++
			}
			for i, value := range m[1:] {
				if i >= len(CPU_FIELDS) {
					break
				}
				tags := opentsdb.TagSet{
					"type": CPU_FIELDS[i],
				}
				if tag_cpu != "" {
					tags["cpu"] = tag_cpu
					Add(&md, "linux.cpu.percpu", value, tags, metadata.Counter, metadata.CHz, cpu_stat_desc[CPU_FIELDS[i]])
				} else {
					Add(&md, "linux.cpu", value, tags, metadata.Counter, metadata.CHz, cpu_stat_desc[CPU_FIELDS[i]])
				}
			}
			if tag_cpu == "" {
				if len(m[1:]) < 3 {
					return nil
				}
				user, err := strconv.Atoi(m[1])
				if err != nil {
					return nil
				}
				nice, err := strconv.Atoi(m[2])
				if err != nil {
					return nil
				}
				system, err := strconv.Atoi(m[3])
				if err != nil {
					return nil
				}
				t_util = user + nice + system
			}
		case m[0] == "intr":
			Add(&md, "linux.intr", m[1], nil, metadata.Counter, metadata.Interupt, "")
		case m[0] == "ctxt":
			Add(&md, "linux.ctxt", m[1], nil, metadata.Counter, metadata.ContextSwitch, "")
		case m[0] == "processes":
			Add(&md, "linux.processes", m[1], nil, metadata.Counter, metadata.Process,
				"The number  of processes and threads created, which includes (but  is not limited  to) those  created by  calls to the  fork() and clone() system calls.")
		case m[0] == "procs_blocked":
			Add(&md, "linux.procs_blocked", m[1], nil, metadata.Gauge, metadata.Process, "The  number of  processes currently blocked, waiting for I/O to complete.")
		}
		return nil
	}); err != nil {
		Error = err
	}
	if num_cores != 0 && t_util != 0 {
		Add(&md, osCPU, t_util/num_cores, nil, metadata.Counter, metadata.Pct, "")
	}
	cpuinfo_index := 0
	if err := readLine("/proc/cpuinfo", func(s string) error {
		m := strings.Split(s, ":")
		if len(m) < 2 {
			return nil
		}
		m[0] = strings.TrimSpace(m[0])
		m[1] = strings.TrimSpace(m[1])
		if m[0] != "cpu MHz" {
			return nil
		}
		tags := opentsdb.TagSet{"cpu": strconv.Itoa(cpuinfo_index)}
		Add(&md, osCPUClock, m[1], tags, metadata.Gauge, metadata.MHz, osCPUClockDesc)
		Add(&md, "linux.cpu.clock", m[1], tags, metadata.Gauge, metadata.MHz, osCPUClockDesc)
		cpuinfo_index++
		return nil
	}); err != nil {
		Error = err
	}
	if err := readLine("/proc/sys/kernel/random/entropy_avail", func(s string) error {
		Add(&md, "linux.entropy_avail", strings.TrimSpace(s), nil, metadata.Gauge, metadata.Entropy, "The remaing amount of entropy available to the system. If it is low or hitting zero processes might be blocked waiting for extropy")
		return nil
	}); err != nil {
		Error = err
	}
	irq_type_desc := map[string]string{
		"NMI": "Non-maskable interrupts.",
		"LOC": "Local timer interrupts.",
		"SPU": "Spurious interrupts.",
		"PMI": "Performance monitoring interrupts.",
		"IWI": "IRQ work interrupts.",
		"RES": "Rescheduling interrupts.",
		"CAL": "Funcation call interupts.",
		"TLB": "TLB (translation lookaside buffer) shootdowns.",
		"TRM": "Thermal event interrupts.",
		"THR": "Threshold APIC interrupts.",
		"MCE": "Machine check exceptions.",
		"MCP": "Machine Check polls.",
	}
	num_cpus := 0
	if err := readLine("/proc/interrupts", func(s string) error {
		cols := strings.Fields(s)
		if num_cpus == 0 {
			num_cpus = len(cols)
			return nil
		} else if len(cols) < 2 {
			return nil
		}
		irq_type := strings.TrimRight(cols[0], ":")
		if _, err := strconv.Atoi(irq_type); err == nil {
			if cols[len(cols)-2] == "PCI-MSI-edge" && strings.Contains(cols[len(cols)-1], "eth") {
				irq_type = cols[len(cols)-1]
			} else {
				// Interrupt type is just a number, ignore.
				return nil
			}
		} else {
			return nil
		}
		for i, val := range cols[1:] {
			if _, err := strconv.Atoi(val); i >= num_cpus || err != nil {
				// All values read, remaining cols contain textual description.
				break
			}
			Add(&md, "linux.interrupts", val, opentsdb.TagSet{"type": irq_type, "cpu": strconv.Itoa(i)}, metadata.Counter, metadata.Interupt, irq_type_desc[irq_type])
		}
		return nil
	}); err != nil {
		Error = err
	}
	if err := readLine("/proc/net/sockstat", func(s string) error {
		cols := strings.Fields(s)
		switch cols[0] {
		case "sockets:":
			if len(cols) < 3 {
				return fmt.Errorf("sockstat: error parsing sockets line")
			}
			Add(&md, "linux.net.sockets.used", cols[2], nil, metadata.Gauge, metadata.Socket, "")
		case "TCP:":
			if len(cols) < 11 {
				return fmt.Errorf("sockstat: error parsing tcp line")
			}
			Add(&md, "linux.net.sockets.tcp_in_use", cols[2], nil, metadata.Gauge, metadata.Socket, "")
			Add(&md, "linux.net.sockets.tcp_orphaned", cols[4], nil, metadata.Gauge, metadata.Socket, "")
			Add(&md, "linux.net.sockets.tcp_time_wait", cols[6], nil, metadata.Gauge, metadata.Socket, "")
			Add(&md, "linux.net.sockets.tcp_allocated", cols[8], nil, metadata.Gauge, metadata.None, "")
			Add(&md, "linux.net.sockets.tcp_mem", cols[10], nil, metadata.Gauge, metadata.None, "")
		case "UDP:":
			if len(cols) < 5 {
				return fmt.Errorf("sockstat: error parsing udp line")
			}
			Add(&md, "linux.net.sockets.udp_in_use", cols[2], nil, metadata.Gauge, metadata.Socket, "")
			Add(&md, "linux.net.sockets.udp_mem", cols[4], nil, metadata.Gauge, metadata.Page, "")
		case "UDPLITE:":
			if len(cols) < 3 {
				return fmt.Errorf("sockstat: error parsing udplite line")
			}
			Add(&md, "linux.net.sockets.udplite_in_use", cols[2], nil, metadata.Gauge, metadata.Socket, "")
		case "RAW:":
			if len(cols) < 3 {
				return fmt.Errorf("sockstat: error parsing raw line")
			}
			Add(&md, "linux.net.sockets.raw_in_use", cols[2], nil, metadata.Gauge, metadata.Socket, "")
		case "FRAG:":
			if len(cols) < 5 {
				return fmt.Errorf("sockstat: error parsing frag line")
			}
			Add(&md, "linux.net.sockets.frag_in_use", cols[2], nil, metadata.Gauge, metadata.Socket, "")
			Add(&md, "linux.net.sockets.frag_mem", cols[4], nil, metadata.Gauge, metadata.Bytes, "")
		}
		return nil
	}); err != nil {
		Error = err
	}
	ln := 0
	var headers []string
	if err := readLine("/proc/net/netstat", func(s string) error {
		cols := strings.Fields(s)
		if ln%2 == 0 {
			headers = cols
		} else {
			if len(cols) < 1 || len(cols) != len(headers) {
				return fmt.Errorf("netstat: parsing failed")
			}
			root := strings.ToLower(strings.TrimSuffix(headers[0], "Ext:"))
			for i, v := range cols[1:] {
				i++
				m := "linux.net.stat." + root + "." + strings.TrimPrefix(strings.ToLower(headers[i]), "tcp")
				Add(&md, m, v, nil, metadata.Counter, metadata.None, "")
			}
		}
		ln++
		return nil
	}); err != nil {
		Error = err
	}
	ln = 0
	if err := readLine("/proc/net/snmp", func(s string) error {
		ln++
		if ln%2 != 0 {
			f := strings.Fields(s)
			if len(f) < 2 {
				return fmt.Errorf("Failed to parse header line")
			}
			headers = f
		} else {
			values := strings.Fields(s)
			if len(values) != len(headers) {
				return fmt.Errorf("Mismatched header and value length")
			}
			proto := strings.ToLower(strings.TrimSuffix(values[0], ":"))
			for i, v := range values {
				if i == 0 {
					continue
				}
				var stype metadata.RateType = metadata.Counter
				stat := strings.ToLower(headers[i])
				if strings.HasPrefix(stat, "rto") {
					stype = metadata.Gauge
				}
				Add(&md, "linux.net.stat."+proto+"."+stat, v, nil, stype, metadata.None, "")
			}
		}
		return nil
	}); err != nil {
		Error = err
	}
	if err := readLine("/proc/sys/fs/file-nr", func(s string) error {
		f := strings.Fields(s)
		if len(f) != 3 {
			return fmt.Errorf("unexpected number of fields")
		}
		v, err := strconv.ParseInt(f[0], 10, 64)
		if err != nil {
			return err
		}
		Add(&md, "linux.fs.open", v, nil, metadata.Gauge, metadata.Count, "The number of files presently open.")
		return nil
	}); err != nil {
		Error = err
	}
	return md, Error
}
<commit_msg>cmd/scollector: more simplifications.<commit_after>package collectors

import (
	"fmt"
	"strconv"
	"strings"

	"bosun.org/_third_party/golang.org/x/sys/unix"
	"bosun.org/metadata"
	"bosun.org/opentsdb"
)

func init() {
	collectors = append(collectors, &IntervalCollector{F: c_procstats_linux})
}

var cpu_fields = []string{
	"user",
	"nice",
	"system",
	"idle",
	"iowait",
	"irq",
	"softirq",
	"steal",
	"guest",
	"guest_nice",
}

var cpu_stat_desc = []string{
	"Normal processes executing in user mode.",
	"Niced processes executing in user mode.",
	"Processes executing in kernel mode.",
	"Twiddling thumbs.",
	"Waiting for I/O to complete.",
	"Servicing interrupts.",
	"Servicing soft irqs.",
	"Involuntary wait.",
	"Running a guest vm.",
	"Running a niced guest vm.",
}

func c_procstats_linux() (opentsdb.MultiDataPoint, error) {
	var md opentsdb.MultiDataPoint
	var Error error
	var sys unix.Sysinfo_t

	unix.Sysinfo(&sys)

	Add(&md, "linux.uptime_total", sys.Uptime, nil, metadata.Gauge, metadata.Second, osSystemUptimeDesc)
	Add(&md, osSystemUptime, sys.Uptime, nil, metadata.Gauge, metadata.Second, osSystemUptimeDesc)
	if err := readLine("/proc/meminfo", func(s string) error {
		s = strings.TrimSuffix(s, " kB")
		m := strings.Split(s, ":")
		if m == nil {
			return nil
		}
		m[1] = strings.TrimSpace(m[1])
		Add(&md, "linux.mem."+strings.ToLower(m[0]), m[1], nil, metadata.Gauge, metadata.KBytes, "")
		return nil
	}); err != nil {
		Error = err
	}
	Add(&md, osMemTotal, sys.Totalram*uint64(sys.Unit), nil, metadata.Gauge, metadata.Bytes, osMemTotalDesc)
	Add(&md, osMemFree, sys.Freeram*uint64(sys.Unit), nil, metadata.Gauge, metadata.Bytes, osMemFreeDesc)
	Add(&md, osMemUsed, (sys.Totalram-sys.Freeram)*uint64(sys.Unit), nil, metadata.Gauge, metadata.Bytes, osMemUsedDesc)
	Add(&md, "linux.loadavg.1_min", sys.Loads[0], nil, metadata.Gauge, metadata.Load, "")
	Add(&md, "linux.loadavg.5_min", sys.Loads[1], nil, metadata.Gauge, metadata.Load, "")
	Add(&md, "linux.loadavg.15_min", sys.Loads[2], nil, metadata.Gauge, metadata.Load, "")
	Add(&md, "linux.loadavg.total_threads", sys.Procs, nil, metadata.Gauge, metadata.Process, "")
	if sys.Totalram != 0 {
		Add(&md, osMemPctFree, (sys.Freeram)/(sys.Totalram)*100, nil, metadata.Gauge, metadata.Pct, osMemFreeDesc)
	}
	if err := readLine("/proc/vmstat", func(s string) error {
		m := strings.Split(s, " ")
		if m == nil {
			return nil
		}
		switch m[0] {
		case "pgpgin", "pgpgout", "pswpin", "pswpout":
			switch {
			case strings.HasSuffix(m[0], "in"):
				Add(&md, "linux.mem."+strings.TrimSuffix(m[0], "in"), m[1], opentsdb.TagSet{"direction": "in"}, metadata.Counter, metadata.Page, "")
			case strings.HasSuffix(m[0], "out"):
				Add(&md, "linux.mem."+strings.TrimSuffix(m[0], "out"), m[1], opentsdb.TagSet{"direction": "out"}, metadata.Counter, metadata.Page, "")
			}
		case "pgfault", "pgmajfault":
			Add(&md, "linux.mem."+m[0], m[1], nil, metadata.Counter, metadata.Page, "")
		default:
			Add(&md, "linux.mem."+m[0], m[1], nil, metadata.Counter, metadata.None, "")
		}
		return nil
	}); err != nil {
		Error = err
	}
	num_cores := 0
	var t_util int
	if err := readLine("/proc/stat", func(s string) error {
		m := strings.Split(s, " ")
		if m == nil {
			return nil
		}
		switch {
		case strings.HasPrefix(m[0], "cpu"):
			tag_cpu := strings.TrimPrefix(m[0], "cpu")
			if tag_cpu != "" {
				num_cores++
			}
			for i, value := range m[1:] {
				if i >= len(cpu_fields) {
					break
				}
				tags := opentsdb.TagSet{
					"type": cpu_fields[i],
				}
				if tag_cpu != "" {
					tags["cpu"] = tag_cpu
					Add(&md, "linux.cpu.percpu", value, tags, metadata.Counter, metadata.CHz, cpu_stat_desc[i])
				} else {
					Add(&md, "linux.cpu", value, tags, metadata.Counter, metadata.CHz, cpu_stat_desc[i])
				}
			}
			if tag_cpu == "" {
				if len(m[1:]) < 3 {
					return nil
				}
				user, err := strconv.Atoi(m[1])
				if err != nil {
					return nil
				}
				nice, err := strconv.Atoi(m[2])
				if err != nil {
					return nil
				}
				system, err := strconv.Atoi(m[3])
				if err != nil {
					return nil
				}
				t_util = user + nice + system
			}
		case m[0] == "intr":
			Add(&md, "linux.intr", m[1], nil, metadata.Counter, metadata.Interupt, "")
		case m[0] == "ctxt":
			Add(&md, "linux.ctxt", m[1], nil, metadata.Counter, metadata.ContextSwitch, "")
		case m[0] == "processes":
			Add(&md, "linux.processes", m[1], nil, metadata.Counter, metadata.Process,
				"The number  of processes and threads created, which includes (but  is not limited  to) those  created by  calls to the  fork() and clone() system calls.")
		case m[0] == "procs_blocked":
			Add(&md, "linux.procs_blocked", m[1], nil, metadata.Gauge, metadata.Process, "The  number of  processes currently blocked, waiting for I/O to complete.")
		}
		return nil
	}); err != nil {
		Error = err
	}
	if num_cores != 0 && t_util != 0 {
		Add(&md, osCPU, t_util/num_cores, nil, metadata.Counter, metadata.Pct, "")
	}
	cpuinfo_index := 0
	if err := readLine("/proc/cpuinfo", func(s string) error {
		m := strings.Split(s, ":")
		if len(m) < 2 {
			return nil
		}
		m[0] = strings.TrimSpace(m[0])
		m[1] = strings.TrimSpace(m[1])
		if m[0] != "cpu MHz" {
			return nil
		}
		tags := opentsdb.TagSet{"cpu": strconv.Itoa(cpuinfo_index)}
		Add(&md, osCPUClock, m[1], tags, metadata.Gauge, metadata.MHz, osCPUClockDesc)
		Add(&md, "linux.cpu.clock", m[1], tags, metadata.Gauge, metadata.MHz, osCPUClockDesc)
		cpuinfo_index++
		return nil
	}); err != nil {
		Error = err
	}
	if err := readLine("/proc/sys/kernel/random/entropy_avail", func(s string) error {
		Add(&md, "linux.entropy_avail", strings.TrimSpace(s), nil, metadata.Gauge, metadata.Entropy, "The remaing amount of entropy available to the system. If it is low or hitting zero processes might be blocked waiting for extropy")
		return nil
	}); err != nil {
		Error = err
	}
	irq_type_desc := map[string]string{
		"NMI": "Non-maskable interrupts.",
		"LOC": "Local timer interrupts.",
		"SPU": "Spurious interrupts.",
		"PMI": "Performance monitoring interrupts.",
		"IWI": "IRQ work interrupts.",
		"RES": "Rescheduling interrupts.",
		"CAL": "Funcation call interupts.",
		"TLB": "TLB (translation lookaside buffer) shootdowns.",
		"TRM": "Thermal event interrupts.",
		"THR": "Threshold APIC interrupts.",
		"MCE": "Machine check exceptions.",
		"MCP": "Machine Check polls.",
	}
	num_cpus := 0
	if err := readLine("/proc/interrupts", func(s string) error {
		cols := strings.Fields(s)
		if num_cpus == 0 {
			num_cpus = len(cols)
			return nil
		} else if len(cols) < 2 {
			return nil
		}
		irq_type := strings.TrimRight(cols[0], ":")
		if _, err := strconv.Atoi(irq_type); err == nil {
			if len(cols) == num_cpus+3 && strings.HasPrefix(cols[num_cpus+1], "IR-") {
				irq_type = cols[len(cols)-1]
			} else {
				// Interrupt type is just a number, ignore.
				return nil
			}
		} else {
			return nil
		}
		for i, val := range cols[1:] {
			if _, err := strconv.Atoi(val); i >= num_cpus || err != nil {
				// All values read, remaining cols contain textual description.
				break
			}
			Add(&md, "linux.interrupts", val, opentsdb.TagSet{"type": irq_type, "cpu": strconv.Itoa(i)}, metadata.Counter, metadata.Interupt, irq_type_desc[irq_type])
		}
		return nil
	}); err != nil {
		Error = err
	}
	if err := readLine("/proc/net/sockstat", func(s string) error {
		cols := strings.Fields(s)
		switch cols[0] {
		case "sockets:":
			if len(cols) < 3 {
				return fmt.Errorf("sockstat: error parsing sockets line")
			}
			Add(&md, "linux.net.sockets.used", cols[2], nil, metadata.Gauge, metadata.Socket, "")
		case "TCP:":
			if len(cols) < 11 {
				return fmt.Errorf("sockstat: error parsing tcp line")
			}
			Add(&md, "linux.net.sockets.tcp_in_use", cols[2], nil, metadata.Gauge, metadata.Socket, "")
			Add(&md, "linux.net.sockets.tcp_orphaned", cols[4], nil, metadata.Gauge, metadata.Socket, "")
			Add(&md, "linux.net.sockets.tcp_time_wait", cols[6], nil, metadata.Gauge, metadata.Socket, "")
			Add(&md, "linux.net.sockets.tcp_allocated", cols[8], nil, metadata.Gauge, metadata.None, "")
			Add(&md, "linux.net.sockets.tcp_mem", cols[10], nil, metadata.Gauge, metadata.None, "")
		case "UDP:":
			if len(cols) < 5 {
				return fmt.Errorf("sockstat: error parsing udp line")
			}
			Add(&md, "linux.net.sockets.udp_in_use", cols[2], nil, metadata.Gauge, metadata.Socket, "")
			Add(&md, "linux.net.sockets.udp_mem", cols[4], nil, metadata.Gauge, metadata.Page, "")
		case "UDPLITE:":
			if len(cols) < 3 {
				return fmt.Errorf("sockstat: error parsing udplite line")
			}
			Add(&md, "linux.net.sockets.udplite_in_use", cols[2], nil, metadata.Gauge, metadata.Socket, "")
		case "RAW:":
			if len(cols) < 3 {
				return fmt.Errorf("sockstat: error parsing raw line")
			}
			Add(&md, "linux.net.sockets.raw_in_use", cols[2], nil, metadata.Gauge, metadata.Socket, "")
		case "FRAG:":
			if len(cols) < 5 {
				return fmt.Errorf("sockstat: error parsing frag line")
			}
			Add(&md, "linux.net.sockets.frag_in_use", cols[2], nil, metadata.Gauge, metadata.Socket, "")
			Add(&md, "linux.net.sockets.frag_mem", cols[4], nil, metadata.Gauge, metadata.Bytes, "")
		}
		return nil
	}); err != nil {
		Error = err
	}
	ln := 0
	var headers []string
	if err := readLine("/proc/net/netstat", func(s string) error {
		cols := strings.Fields(s)
		if ln%2 == 0 {
			headers = cols
		} else {
			if len(cols) < 1 || len(cols) != len(headers) {
				return fmt.Errorf("netstat: parsing failed")
			}
			root := strings.ToLower(strings.TrimSuffix(headers[0], "Ext:"))
			for i, v := range cols[1:] {
				i++
				m := "linux.net.stat." + root + "." + strings.TrimPrefix(strings.ToLower(headers[i]), "tcp")
				Add(&md, m, v, nil, metadata.Counter, metadata.None, "")
			}
		}
		ln++
		return nil
	}); err != nil {
		Error = err
	}
	ln = 0
	if err := readLine("/proc/net/snmp", func(s string) error {
		ln++
		if ln%2 != 0 {
			f := strings.Fields(s)
			if len(f) < 2 {
				return fmt.Errorf("Failed to parse header line")
			}
			headers = f
		} else {
			values := strings.Fields(s)
			if len(values) != len(headers) {
				return fmt.Errorf("Mismatched header and value length")
			}
			proto := strings.ToLower(strings.TrimSuffix(values[0], ":"))
			for i, v := range values {
				if i == 0 {
					continue
				}
				var stype metadata.RateType = metadata.Counter
				stat := strings.ToLower(headers[i])
				if strings.HasPrefix(stat, "rto") {
					stype = metadata.Gauge
				}
				Add(&md, "linux.net.stat."+proto+"."+stat, v, nil, stype, metadata.None, "")
			}
		}
		return nil
	}); err != nil {
		Error = err
	}
	if err := readLine("/proc/sys/fs/file-nr", func(s string) error {
		f := strings.Fields(s)
		if len(f) != 3 {
			return fmt.Errorf("unexpected number of fields")
		}
		v, err := strconv.ParseInt(f[0], 10, 64)
		if err != nil {
			return err
		}
		Add(&md, "linux.fs.open", v, nil, metadata.Gauge, metadata.Count, "The number of files presently open.")
		return nil
	}); err != nil {
		Error = err
	}
	return md, Error
}
<|endoftext|>