<commit_before>package generate

import (
	"math/rand"
	"reflect"
	"testing"
	"time"
)

const targetTestVersion = 0

func TestVersionValidation(t *testing.T) {
	if testVersion != targetTestVersion {
		t.Fatalf("Found testVersion = %v, want %v\n", testVersion, targetTestVersion)
	}
}

func TestRandStringBytesMaskLength(t *testing.T) {
	src := rand.NewSource(time.Now().UnixNano())
	for _, test := range testStringLengthCases {
		observed := RandStringBytesMask(src, test.Tested.Value.(int))
		t.Logf("Running test for `%s`\n", test.Description)
		if len(observed) != test.Expected.Value {
			t.Fatalf("%s(%v):\n"+
				"Brief (%s)\n"+
				"Observed: %t\n"+
				"Expected: %t\n",
				"TestRandStringBytesMask", test.Tested.Value,
				test.Description, observed, test.Expected.Value)
		}
	}
}

func TestRandStringBytesMaskType(t *testing.T) {
	src := rand.NewSource(time.Now().UnixNano())
	for _, test := range testStringLengthCases {
		observed := RandStringBytesMask(src, test.Tested.Value.(int))
		t.Logf("Running test for `%s`\n", test.Description)
		typecheck := reflect.TypeOf(observed)
		if typecheck.Kind() != reflect.String {
			t.Fatalf("%s(%v):\n"+
				"Brief (%s)\n"+
				"Observed: %t\n"+
				"Expected: %t\n",
				"TestRandStringBytesMask", test.Tested.Value,
				test.Description, observed, test.Expected.Value)
		}
	}
}

// TODO: figure out why benchmarks are not working
func benchmarkRandStringBytesMask(n int, b *testing.B) {
	// Create the new source for random generation
	src := rand.NewSource(time.Now().UnixNano())
	// Run the RandStringBytesMask function b.N times
	for n := 0; n < b.N; n++ {
		RandStringBytesMask(src, n)
	}
}

func BenchmarkRandStringBytesMask2(b *testing.B)  { benchmarkRandStringBytesMask(2, b) }
func BenchmarkRandStringBytesMask4(b *testing.B)  { benchmarkRandStringBytesMask(4, b) }
func BenchmarkRandStringBytesMask8(b *testing.B)  { benchmarkRandStringBytesMask(8, b) }
func BenchmarkRandStringBytesMask16(b *testing.B) { benchmarkRandStringBytesMask(16, b) }
func BenchmarkRandStringBytesMask32(b *testing.B) { benchmarkRandStringBytesMask(32, b) }
func BenchmarkRandStringBytesMask64(b *testing.B) { benchmarkRandStringBytesMask(64, b) }
<commit_msg>turns out vscode doesn't run benchmarks by itself atm<commit_after>package generate

import (
	"math/rand"
	"reflect"
	"testing"
	"time"
)

const targetTestVersion = 0

func TestVersionValidation(t *testing.T) {
	if testVersion != targetTestVersion {
		t.Fatalf("Found testVersion = %v, want %v\n", testVersion, targetTestVersion)
	}
}

func TestRandStringBytesMaskLength(t *testing.T) {
	src := rand.NewSource(time.Now().UnixNano())
	for _, test := range testStringLengthCases {
		observed := RandStringBytesMask(src, test.Tested.Value.(int))
		t.Logf("Running test for `%s`\n", test.Description)
		if len(observed) != test.Expected.Value {
			t.Fatalf("%s(%v):\n"+
				"Brief (%s)\n"+
				"Observed: %t\n"+
				"Expected: %t\n",
				"TestRandStringBytesMask", test.Tested.Value,
				test.Description, observed, test.Expected.Value)
		}
	}
}

func TestRandStringBytesMaskType(t *testing.T) {
	src := rand.NewSource(time.Now().UnixNano())
	for _, test := range testStringLengthCases {
		observed := RandStringBytesMask(src, test.Tested.Value.(int))
		t.Logf("Running test for `%s`\n", test.Description)
		typecheck := reflect.TypeOf(observed)
		if typecheck.Kind() != reflect.String {
			t.Fatalf("%s(%v):\n"+
				"Brief (%s)\n"+
				"Observed: %t\n"+
				"Expected: %t\n",
				"TestRandStringBytesMask", test.Tested.Value,
				test.Description, observed, test.Expected.Value)
		}
	}
}

func benchmarkRandStringBytesMask(n int, b *testing.B) {
	// Create the new source for random generation
	src := rand.NewSource(time.Now().UnixNano())
	// Run the RandStringBytesMask function b.N times
	for n := 0; n < b.N; n++ {
		RandStringBytesMask(src, n)
	}
}

func BenchmarkRandStringBytesMask32(b *testing.B) { benchmarkRandStringBytesMask(32, b) }
<|endoftext|>


<commit_before>package handlers

import (
	"github.com/go-openapi/runtime/middleware"
	coreclusters "github.com/radanalyticsio/oshinko-core/clusters"
	osa "github.com/radanalyticsio/oshinko-rest/helpers/authentication"
	oe "github.com/radanalyticsio/oshinko-rest/helpers/errors"
	"github.com/radanalyticsio/oshinko-rest/helpers/info"
	"github.com/radanalyticsio/oshinko-core/clusterconfigs"
	"github.com/radanalyticsio/oshinko-rest/models"
	apiclusters "github.com/radanalyticsio/oshinko-rest/restapi/operations/clusters"
	"strings"
)

const nameSpaceMsg = "cannot determine target openshift namespace"
const clientMsg = "unable to create an openshift client"

func generalErr(err error, title, msg string, code int32) *models.ErrorResponse {
	if err != nil {
		msg = msg + ", err: " + err.Error()
	}
	return oe.NewSingleErrorResponse(code, title, msg)
}

func tostrptr(val string) *string {
	v := val
	return &v
}

func singleClusterResponse(sc coreclusters.SparkCluster) *models.SingleCluster {

	addpod := func(p coreclusters.SparkPod) *models.ClusterModelPodsItems0 {
		pod := new(models.ClusterModelPodsItems0)
		pod.IP = tostrptr(p.IP)
		pod.Status = tostrptr(p.Status)
		pod.Type = tostrptr(p.Type)
		return pod
	}

	// Build the response
	cluster := &models.SingleCluster{&models.ClusterModel{}}
	cluster.Cluster.Name = tostrptr(sc.Name)
	cluster.Cluster.MasterURL = tostrptr(sc.MasterURL)
	cluster.Cluster.MasterWebURL = tostrptr(sc.MasterWebURL)

	cluster.Cluster.Status = tostrptr(sc.Status)

	cluster.Cluster.Pods = []*models.ClusterModelPodsItems0{}
	for i := range sc.Pods {
		cluster.Cluster.Pods = append(cluster.Cluster.Pods, addpod(sc.Pods[i]))
	}

	cluster.Cluster.Config = &models.NewClusterConfig{
		SparkMasterConfig: sc.Config.SparkMasterConfig,
		SparkWorkerConfig: sc.Config.SparkWorkerConfig,
		MasterCount: int64(sc.Config.MasterCount),
		WorkerCount: int64(sc.Config.WorkerCount),
		Name: sc.Config.Name,
	}
	return cluster
}

func assignConfig(config *models.NewClusterConfig) *clusterconfigs.ClusterConfig {
	if config == nil {
		return nil
	}
	result := &clusterconfigs.ClusterConfig{
		Name: config.Name,
		MasterCount: int(config.MasterCount),
		WorkerCount: int(config.WorkerCount),
		SparkMasterConfig: config.SparkMasterConfig,
		SparkWorkerConfig: config.SparkWorkerConfig,
	}
	return result
}

// CreateClusterResponse create a cluster and return the representation
func CreateClusterResponse(params apiclusters.CreateClusterParams) middleware.Responder {

	// Do this so that we only have to specify the error code when we build ErrorResponse
	reterr := func(err *models.ErrorResponse) *apiclusters.CreateClusterDefault {
		return apiclusters.NewCreateClusterDefault(int(*err.Errors[0].Status)).WithPayload(err)
	}

	// Convenience wrapper for create failure
	fail := func(err error, msg string, code int32) *models.ErrorResponse {
		return generalErr(err, "cannot create cluster", msg, code)
	}

	//code := func(err error) int32 {
	//	if strings.Index(err.Error(), "already exists") != -1 {
	//		return 409
	//	}
	//	return 500
	//}
	const imageMsg = "cannot determine name of spark image"

	clustername := *params.Cluster.Name

	namespace, err := info.GetNamespace()
	if namespace == "" || err != nil {
		return reterr(fail(err, nameSpaceMsg, 500))
	}

	image, err := info.GetSparkImage()
	if image == "" || err != nil {
		return reterr(fail(err, imageMsg, 500))
	}

	client, err := osa.GetKubeClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	osclient, err := osa.GetOpenShiftClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	config := assignConfig(params.Cluster.Config)
	sc, err := coreclusters.CreateCluster(clustername, namespace, image, config, osclient, client)
	if err != nil {
		return reterr(fail(err, "", 409))
	}
	return apiclusters.NewCreateClusterCreated().WithLocation(sc.Href).WithPayload(singleClusterResponse(sc))
}

// DeleteClusterResponse delete a cluster
func DeleteClusterResponse(params apiclusters.DeleteSingleClusterParams) middleware.Responder {

	// Do this so that we only have to specify the error code when we build ErrorResponse
	reterr := func(err *models.ErrorResponse) *apiclusters.DeleteSingleClusterDefault {
		return apiclusters.NewDeleteSingleClusterDefault(int(*err.Errors[0].Status)).WithPayload(err)
	}

	// Convenience wrapper for delete failure
	fail := func(err error, msg string, code int32) *models.ErrorResponse {
		return generalErr(err, "cluster deletion failed", msg, code)
	}

	namespace, err := info.GetNamespace()
	if namespace == "" || err != nil {
		return reterr(fail(err, nameSpaceMsg, 500))
	}

	osclient, err := osa.GetOpenShiftClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	client, err := osa.GetKubeClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	info, err := coreclusters.DeleteCluster(params.Name, namespace, osclient, client)
	if err != nil && strings.Index(err.Error(), "no such cluster") != -1 {
		return reterr(fail(err, "No such cluster", 404))
	} else if err != nil {
		return reterr(fail(err, "", 409))
	}
	if info != "" {
		return reterr(fail(nil, "deletion may be incomplete: " + info, 500))
	}
	return apiclusters.NewDeleteSingleClusterNoContent()
}

// FindClustersResponse find a cluster and return its representation
func FindClustersResponse(params apiclusters.FindClustersParams) middleware.Responder {

	// Do this so that we only have to specify the error code when we build ErrorResponse
	reterr := func(err *models.ErrorResponse) *apiclusters.FindClustersDefault {
		return apiclusters.NewFindClustersDefault(int(*err.Errors[0].Status)).WithPayload(err)
	}

	// Convenience wrapper for list failure
	fail := func(err error, msg string, code int32) *models.ErrorResponse {
		return generalErr(err, "cannot list clusters", msg, code)
	}

	namespace, err := info.GetNamespace()
	if namespace == "" || err != nil {
		return reterr(fail(err, nameSpaceMsg, 500))
	}

	client, err := osa.GetKubeClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}
	scs, err := coreclusters.FindClusters(namespace, client)
	if err != nil {
		return reterr(fail(err, "", 409))
	}

	// Create the payload that we're going to write into for the response
	payload := apiclusters.FindClustersOKBodyBody{}
	payload.Clusters = []*apiclusters.ClustersItems0{}
	for idx := range(scs) {
		clt := new(apiclusters.ClustersItems0)
		clt.Href = &scs[idx].Href
		clt.MasterURL = &scs[idx].MasterURL
		clt.MasterWebURL = &scs[idx].MasterWebURL
		clt.Name = &scs[idx].Name
		clt.Status = &scs[idx].Status
		wc := int64(scs[idx].WorkerCount)
		clt.WorkerCount = &wc
		payload.Clusters = append(payload.Clusters, clt)
	}

	return apiclusters.NewFindClustersOK().WithPayload(payload)
}

// FindSingleClusterResponse find a cluster and return its representation
func FindSingleClusterResponse(params apiclusters.FindSingleClusterParams) middleware.Responder {

	clustername := params.Name

	// Do this so that we only have to specify the error code when we build ErrorResponse
	reterr := func(err *models.ErrorResponse) *apiclusters.FindSingleClusterDefault {
		return apiclusters.NewFindSingleClusterDefault(int(*err.Errors[0].Status)).WithPayload(err)
	}

	// Convenience wrapper for get failure
	fail := func(err error, msg string, code int32) *models.ErrorResponse {
		return generalErr(err, "Cannot get cluster", msg, code)
	}

	namespace, err := info.GetNamespace()
	if namespace == "" || err != nil {
		return reterr(fail(err, nameSpaceMsg, 500))
	}

	osclient, err := osa.GetOpenShiftClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	client, err := osa.GetKubeClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	sc, err := coreclusters.FindSingleCluster(clustername, namespace, osclient, client)
	if err != nil && strings.Index(err.Error(), "no such cluster") != -1 {
		return reterr(fail(err, "No such cluster", 404))
	} else if err != nil {
		return reterr(fail(err, "", 409))
	}

	return apiclusters.NewFindSingleClusterOK().WithPayload(singleClusterResponse(sc))
}

// UpdateSingleClusterResponse update a cluster and return the new representation
func UpdateSingleClusterResponse(params apiclusters.UpdateSingleClusterParams) middleware.Responder {

	// Do this so that we only have to specify the error code when we build ErrorResponse
	reterr := func(err *models.ErrorResponse) *apiclusters.UpdateSingleClusterDefault {
		return apiclusters.NewUpdateSingleClusterDefault(int(*err.Errors[0].Status)).WithPayload(err)
	}

	// Convenience wrapper for update failure
	fail := func(err error, msg string, code int32) *models.ErrorResponse {
		return generalErr(err, "cannot update cluster", msg, code)
	}

	const clusterNameMsg = "changing the cluster name is not supported"

	clustername := params.Name

	// Before we do further checks, make sure that we have deploymentconfigs
	// If either the master or the worker deploymentconfig are missing, we
	// assume that the cluster is missing. These are the base objects that
	// we use to create a cluster
	namespace, err := info.GetNamespace()
	if namespace == "" || err != nil {
		return reterr(fail(err, nameSpaceMsg, 500))
	}

	osclient, err := osa.GetOpenShiftClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	client, err := osa.GetKubeClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	// Simple things first. At this time we do not support cluster name change and
	// we do not suppport scaling the master count (likely need HA setup for that to make sense)
	if clustername != *params.Cluster.Name {
		return reterr(fail(nil, clusterNameMsg, 409))
	}

	config := assignConfig(params.Cluster.Config)
	sc, err := coreclusters.UpdateCluster(clustername, namespace, config, osclient, client)
	if err != nil && strings.Index(err.Error(), "no such cluster") != -1 {
		return reterr(fail(err, "No such cluster", 404))
	} else if err != nil {
		return reterr(fail(err, "", 409))
	}
	return apiclusters.NewUpdateSingleClusterAccepted().WithPayload(singleClusterResponse(sc))
}
<commit_msg>restoring 404 error on cluster not found (pretty message)<commit_after>package handlers

import (
	"github.com/go-openapi/runtime/middleware"
	coreclusters "github.com/radanalyticsio/oshinko-core/clusters"
	osa "github.com/radanalyticsio/oshinko-rest/helpers/authentication"
	oe "github.com/radanalyticsio/oshinko-rest/helpers/errors"
	"github.com/radanalyticsio/oshinko-rest/helpers/info"
	"github.com/radanalyticsio/oshinko-core/clusterconfigs"
	"github.com/radanalyticsio/oshinko-rest/models"
	apiclusters "github.com/radanalyticsio/oshinko-rest/restapi/operations/clusters"
	"strings"
)

const nameSpaceMsg = "cannot determine target openshift namespace"
const clientMsg = "unable to create an openshift client"

func generalErr(err error, title, msg string, code int32) *models.ErrorResponse {
	if err != nil {
		if len(msg) > 0 {
			msg = msg + ", "
		}
		msg = msg + "err: " + err.Error()
	}
	return oe.NewSingleErrorResponse(code, title, msg)
}

func tostrptr(val string) *string {
	v := val
	return &v
}

func singleClusterResponse(sc coreclusters.SparkCluster) *models.SingleCluster {

	addpod := func(p coreclusters.SparkPod) *models.ClusterModelPodsItems0 {
		pod := new(models.ClusterModelPodsItems0)
		pod.IP = tostrptr(p.IP)
		pod.Status = tostrptr(p.Status)
		pod.Type = tostrptr(p.Type)
		return pod
	}

	// Build the response
	cluster := &models.SingleCluster{&models.ClusterModel{}}
	cluster.Cluster.Name = tostrptr(sc.Name)
	cluster.Cluster.MasterURL = tostrptr(sc.MasterURL)
	cluster.Cluster.MasterWebURL = tostrptr(sc.MasterWebURL)

	cluster.Cluster.Status = tostrptr(sc.Status)

	cluster.Cluster.Pods = []*models.ClusterModelPodsItems0{}
	for i := range sc.Pods {
		cluster.Cluster.Pods = append(cluster.Cluster.Pods, addpod(sc.Pods[i]))
	}

	cluster.Cluster.Config = &models.NewClusterConfig{
		SparkMasterConfig: sc.Config.SparkMasterConfig,
		SparkWorkerConfig: sc.Config.SparkWorkerConfig,
		MasterCount: int64(sc.Config.MasterCount),
		WorkerCount: int64(sc.Config.WorkerCount),
		Name: sc.Config.Name,
	}
	return cluster
}

func assignConfig(config *models.NewClusterConfig) *clusterconfigs.ClusterConfig {
	if config == nil {
		return nil
	}
	result := &clusterconfigs.ClusterConfig{
		Name: config.Name,
		MasterCount: int(config.MasterCount),
		WorkerCount: int(config.WorkerCount),
		SparkMasterConfig: config.SparkMasterConfig,
		SparkWorkerConfig: config.SparkWorkerConfig,
	}
	return result
}

// CreateClusterResponse create a cluster and return the representation
func CreateClusterResponse(params apiclusters.CreateClusterParams) middleware.Responder {

	// Do this so that we only have to specify the error code when we build ErrorResponse
	reterr := func(err *models.ErrorResponse) *apiclusters.CreateClusterDefault {
		return apiclusters.NewCreateClusterDefault(int(*err.Errors[0].Status)).WithPayload(err)
	}

	// Convenience wrapper for create failure
	fail := func(err error, msg string, code int32) *models.ErrorResponse {
		return generalErr(err, "cannot create cluster", msg, code)
	}

	//code := func(err error) int32 {
	//	if strings.Index(err.Error(), "already exists") != -1 {
	//		return 409
	//	}
	//	return 500
	//}
	const imageMsg = "cannot determine name of spark image"

	clustername := *params.Cluster.Name

	namespace, err := info.GetNamespace()
	if namespace == "" || err != nil {
		return reterr(fail(err, nameSpaceMsg, 500))
	}

	image, err := info.GetSparkImage()
	if image == "" || err != nil {
		return reterr(fail(err, imageMsg, 500))
	}

	client, err := osa.GetKubeClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	osclient, err := osa.GetOpenShiftClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	config := assignConfig(params.Cluster.Config)
	sc, err := coreclusters.CreateCluster(clustername, namespace, image, config, osclient, client)
	if err != nil {
		return reterr(fail(err, "", 409))
	}
	return apiclusters.NewCreateClusterCreated().WithLocation(sc.Href).WithPayload(singleClusterResponse(sc))
}

// DeleteClusterResponse delete a cluster
func DeleteClusterResponse(params apiclusters.DeleteSingleClusterParams) middleware.Responder {

	// Do this so that we only have to specify the error code when we build ErrorResponse
	reterr := func(err *models.ErrorResponse) *apiclusters.DeleteSingleClusterDefault {
		return apiclusters.NewDeleteSingleClusterDefault(int(*err.Errors[0].Status)).WithPayload(err)
	}

	// Convenience wrapper for delete failure
	fail := func(err error, msg string, code int32) *models.ErrorResponse {
		return generalErr(err, "cluster deletion failed", msg, code)
	}

	namespace, err := info.GetNamespace()
	if namespace == "" || err != nil {
		return reterr(fail(err, nameSpaceMsg, 500))
	}

	osclient, err := osa.GetOpenShiftClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	client, err := osa.GetKubeClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	info, err := coreclusters.DeleteCluster(params.Name, namespace, osclient, client)
	if err != nil && strings.Index(err.Error(), "no such cluster") != -1 {
		return reterr(fail(err, "", 404))
	} else if err != nil {
		return reterr(fail(err, "", 409))
	}
	if info != "" {
		return reterr(fail(nil, "deletion may be incomplete: " + info, 500))
	}
	return apiclusters.NewDeleteSingleClusterNoContent()
}

// FindClustersResponse find a cluster and return its representation
func FindClustersResponse(params apiclusters.FindClustersParams) middleware.Responder {

	// Do this so that we only have to specify the error code when we build ErrorResponse
	reterr := func(err *models.ErrorResponse) *apiclusters.FindClustersDefault {
		return apiclusters.NewFindClustersDefault(int(*err.Errors[0].Status)).WithPayload(err)
	}

	// Convenience wrapper for list failure
	fail := func(err error, msg string, code int32) *models.ErrorResponse {
		return generalErr(err, "cannot list clusters", msg, code)
	}

	namespace, err := info.GetNamespace()
	if namespace == "" || err != nil {
		return reterr(fail(err, nameSpaceMsg, 500))
	}

	client, err := osa.GetKubeClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}
	scs, err := coreclusters.FindClusters(namespace, client)
	if err != nil {
		return reterr(fail(err, "", 409))
	}

	// Create the payload that we're going to write into for the response
	payload := apiclusters.FindClustersOKBodyBody{}
	payload.Clusters = []*apiclusters.ClustersItems0{}
	for idx := range(scs) {
		clt := new(apiclusters.ClustersItems0)
		clt.Href = &scs[idx].Href
		clt.MasterURL = &scs[idx].MasterURL
		clt.MasterWebURL = &scs[idx].MasterWebURL
		clt.Name = &scs[idx].Name
		clt.Status = &scs[idx].Status
		wc := int64(scs[idx].WorkerCount)
		clt.WorkerCount = &wc
		payload.Clusters = append(payload.Clusters, clt)
	}

	return apiclusters.NewFindClustersOK().WithPayload(payload)
}

// FindSingleClusterResponse find a cluster and return its representation
func FindSingleClusterResponse(params apiclusters.FindSingleClusterParams) middleware.Responder {

	clustername := params.Name

	// Do this so that we only have to specify the error code when we build ErrorResponse
	reterr := func(err *models.ErrorResponse) *apiclusters.FindSingleClusterDefault {
		return apiclusters.NewFindSingleClusterDefault(int(*err.Errors[0].Status)).WithPayload(err)
	}

	// Convenience wrapper for get failure
	fail := func(err error, msg string, code int32) *models.ErrorResponse {
		return generalErr(err, "Cannot get cluster", msg, code)
	}

	namespace, err := info.GetNamespace()
	if namespace == "" || err != nil {
		return reterr(fail(err, nameSpaceMsg, 500))
	}

	osclient, err := osa.GetOpenShiftClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	client, err := osa.GetKubeClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	sc, err := coreclusters.FindSingleCluster(clustername, namespace, osclient, client)
	if err != nil && strings.Index(err.Error(), "no such cluster") != -1 {
		return reterr(fail(err, "", 404))
	} else if err != nil {
		return reterr(fail(err, "", 409))
	}

	return apiclusters.NewFindSingleClusterOK().WithPayload(singleClusterResponse(sc))
}

// UpdateSingleClusterResponse update a cluster and return the new representation
func UpdateSingleClusterResponse(params apiclusters.UpdateSingleClusterParams) middleware.Responder {

	// Do this so that we only have to specify the error code when we build ErrorResponse
	reterr := func(err *models.ErrorResponse) *apiclusters.UpdateSingleClusterDefault {
		return apiclusters.NewUpdateSingleClusterDefault(int(*err.Errors[0].Status)).WithPayload(err)
	}

	// Convenience wrapper for update failure
	fail := func(err error, msg string, code int32) *models.ErrorResponse {
		return generalErr(err, "cannot update cluster", msg, code)
	}

	const clusterNameMsg = "changing the cluster name is not supported"

	clustername := params.Name

	// Before we do further checks, make sure that we have deploymentconfigs
	// If either the master or the worker deploymentconfig are missing, we
	// assume that the cluster is missing. These are the base objects that
	// we use to create a cluster
	namespace, err := info.GetNamespace()
	if namespace == "" || err != nil {
		return reterr(fail(err, nameSpaceMsg, 500))
	}

	osclient, err := osa.GetOpenShiftClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	client, err := osa.GetKubeClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	// Simple things first. At this time we do not support cluster name change and
	// we do not suppport scaling the master count (likely need HA setup for that to make sense)
	if clustername != *params.Cluster.Name {
		return reterr(fail(nil, clusterNameMsg, 409))
	}

	config := assignConfig(params.Cluster.Config)
	sc, err := coreclusters.UpdateCluster(clustername, namespace, config, osclient, client)
	if err != nil && strings.Index(err.Error(), "no such cluster") != -1 {
		return reterr(fail(err, "", 404))
	} else if err != nil {
		return reterr(fail(err, "", 409))
	}
	return apiclusters.NewUpdateSingleClusterAccepted().WithPayload(singleClusterResponse(sc))
}
<|endoftext|>


<commit_before>package discover

import (
	"encoding/hex"
	"errors"
	"fmt"
	"log"
	"net"
	"strings"
	"sync"
	"time"

	"github.com/calmh/syncthing/buffers"
)

const (
	AnnouncementPort = 21025
	Debug            = false
)

type Discoverer struct {
	MyID             string
	ListenPort       int
	BroadcastIntv    time.Duration
	ExtBroadcastIntv time.Duration

	conn         *net.UDPConn
	registry     map[string][]string
	registryLock sync.RWMutex
	extServer    string
}

var (
	ErrIncorrectMagic = errors.New("Incorrect magic number")
)

// We tolerate a certain amount of errors because we might be running on
// laptops that sleep and wake, have intermittent network connectivity, etc.
// When we hit this many errors in succession, we stop.
const maxErrors = 30

func NewDiscoverer(id string, port int, extServer string) (*Discoverer, error) {
	local := &net.UDPAddr{IP: nil, Port: AnnouncementPort}
	conn, err := net.ListenUDP("udp", local)
	if err != nil {
		return nil, err
	}

	disc := &Discoverer{
		MyID:             id,
		ListenPort:       port,
		BroadcastIntv:    30 * time.Second,
		ExtBroadcastIntv: 1800 * time.Second,

		conn:      conn,
		registry:  make(map[string][]string),
		extServer: extServer,
	}

	go disc.recvAnnouncements()

	if disc.ListenPort > 0 {
		go disc.sendAnnouncements()
	}
	if len(disc.extServer) > 0 {
		go disc.sendExtAnnouncements()
	}

	return disc, nil
}

func (d *Discoverer) sendAnnouncements() {
	var pkt = AnnounceV2{AnnouncementMagicV2, d.MyID, []Address{{nil, 22000}}}
	var buf = pkt.MarshalXDR()
	var errCounter = 0
	var err error

	for errCounter < maxErrors {
		for _, ipStr := range allBroadcasts() {
			var addrStr = ipStr + ":21025"

			remote, err := net.ResolveUDPAddr("udp4", addrStr)
			if err != nil {
				log.Printf("discover/external: %v; no external announcements", err)
				return
			}

			if Debug {
				fmt.Println("send announcement -> ", remote)
			}
			_, _, err = d.conn.WriteMsgUDP(buf, nil, remote)
			if err != nil {
				log.Println("discover/write: warning:", err)
				errCounter++
			} else {
				errCounter = 0
			}
		}
		time.Sleep(d.BroadcastIntv)
	}
	log.Println("discover/write: local: stopping due to too many errors:", err)
}

func (d *Discoverer) sendExtAnnouncements() {
	remote, err := net.ResolveUDPAddr("udp", d.extServer)
	if err != nil {
		log.Printf("discover/external: %v; no external announcements", err)
		return
	}

	var pkt = AnnounceV2{AnnouncementMagicV2, d.MyID, []Address{{nil, 22000}}}
	var buf = pkt.MarshalXDR()
	var errCounter = 0

	for errCounter < maxErrors {
		if Debug {
			fmt.Println("send announcement -> ", remote)
		}
		_, _, err = d.conn.WriteMsgUDP(buf, nil, remote)
		if err != nil {
			log.Println("discover/write: warning:", err)
			errCounter++
		} else {
			errCounter = 0
		}
		time.Sleep(d.ExtBroadcastIntv)
	}
	log.Println("discover/write: %v: stopping due to too many errors:", remote, err)
}

func (d *Discoverer) recvAnnouncements() {
	var buf = make([]byte, 1024)
	var errCounter = 0
	var err error
	for errCounter < maxErrors {
		n, addr, err := d.conn.ReadFromUDP(buf)
		if err != nil {
			errCounter++
			time.Sleep(time.Second)
			continue
		}

		if Debug {
			log.Printf("read announcement:\n%s", hex.Dump(buf[:n]))
		}

		var pkt AnnounceV2
		err = pkt.UnmarshalXDR(buf[:n])
		if err != nil {
			errCounter++
			time.Sleep(time.Second)
			continue
		}

		if Debug {
			log.Printf("read announcement: %#v", pkt)
		}

		errCounter = 0

		if pkt.NodeID != d.MyID {
			var addrs []string
			for _, a := range pkt.Addresses {
				var nodeAddr string
				if len(a.IP) > 0 {
					nodeAddr = fmt.Sprintf("%s:%d", ipStr(a.IP), a.Port)
				} else {
					nodeAddr = fmt.Sprintf("%s:%d", addr.IP.String(), a.Port)
				}
				addrs = append(addrs, nodeAddr)
			}
			if Debug {
				log.Printf("register: %#v", addrs)
			}
			d.registryLock.Lock()
			d.registry[pkt.NodeID] = addrs
			d.registryLock.Unlock()
		}
	}
	log.Println("discover/read: stopping due to too many errors:", err)
}

func (d *Discoverer) externalLookup(node string) []string {
	extIP, err := net.ResolveUDPAddr("udp", d.extServer)
	if err != nil {
		log.Printf("discover/external: %v; no external lookup", err)
		return nil
	}

	conn, err := net.DialUDP("udp", nil, extIP)
	if err != nil {
		log.Printf("discover/external: %v; no external lookup", err)
		return nil
	}
	defer conn.Close()

	err = conn.SetDeadline(time.Now().Add(5 * time.Second))
	if err != nil {
		log.Printf("discover/external: %v; no external lookup", err)
		return nil
	}

	buf := QueryV2{QueryMagicV2, node}.MarshalXDR()
	_, err = conn.Write(buf)
	if err != nil {
		log.Printf("discover/external: %v; no external lookup", err)
		return nil
	}
	buffers.Put(buf)

	buf = buffers.Get(256)
	defer buffers.Put(buf)

	n, err := conn.Read(buf)
	if err != nil {
		if err, ok := err.(net.Error); ok && err.Timeout() {
			// Expected if the server doesn't know about requested node ID
			return nil
		}
		log.Printf("discover/external/read: %v; no external lookup", err)
		return nil
	}

	if Debug {
		log.Printf("read external:\n%s", hex.Dump(buf[:n]))
	}

	var pkt AnnounceV2
	err = pkt.UnmarshalXDR(buf[:n])
	if err != nil {
		log.Println("discover/external/decode:", err)
		return nil
	}

	if Debug {
		log.Printf("read external: %#v", pkt)
	}

	var addrs []string
	for _, a := range pkt.Addresses {
		var nodeAddr string
		if len(a.IP) > 0 {
			nodeAddr = fmt.Sprintf("%s:%d", ipStr(a.IP), a.Port)
		}
		addrs = append(addrs, nodeAddr)
	}
	return addrs
}

func (d *Discoverer) Lookup(node string) []string {
	d.registryLock.Lock()
	addr, ok := d.registry[node]
	d.registryLock.Unlock()

	if ok {
		return addr
	} else if len(d.extServer) != 0 {
		// We might want to cache this, but not permanently so it needs some intelligence
		return d.externalLookup(node)
	}
	return nil
}

func ipStr(ip []byte) string {
	var f = "%d"
	var s = "."
	if len(ip) > 4 {
		f = "%x"
		s = ":"
	}
	var ss = make([]string, len(ip))
	for i := range ip {
		ss[i] = fmt.Sprintf(f, ip[i])
	}
	return strings.Join(ss, s)
}

func allBroadcasts() []string {
	var bcasts = make(map[string]bool)
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		return nil
	}

	for _, addr := range addrs {
		switch {
		case strings.HasPrefix(addr.String(), "127."):
			// Ignore v4 localhost

		case strings.Contains(addr.String(), ":"):
			// Ignore all v6, because we need link local multicast there which I haven't implemented

		default:
			if in, ok := addr.(*net.IPNet); ok {
				il := len(in.IP) - 1
				ml := len(in.Mask) - 1
				for i := range in.Mask {
					in.IP[il-i] = in.IP[il-i] | ^in.Mask[ml-i]
				}
				parts := strings.Split(in.String(), "/")
				bcasts[parts[0]] = true
			}
		}
	}

	var l []string
	for ip := range bcasts {
		l = append(l, ip)
	}
	return l
}
<commit_msg>Respond to local announces of new nodes<commit_after>package discover

import (
	"encoding/hex"
	"errors"
	"fmt"
	"log"
	"net"
	"strings"
	"sync"
	"time"

	"github.com/calmh/syncthing/buffers"
)

const (
	AnnouncementPort = 21025
	Debug            = false
)

type Discoverer struct {
	MyID             string
	ListenPort       int
	BroadcastIntv    time.Duration
	ExtBroadcastIntv time.Duration

	conn         *net.UDPConn
	registry     map[string][]string
	registryLock sync.RWMutex
	extServer    string

	localBroadcastTick  <-chan time.Time
	forcedBroadcastTick chan time.Time
}

var (
	ErrIncorrectMagic = errors.New("Incorrect magic number")
)

// We tolerate a certain amount of errors because we might be running on
// laptops that sleep and wake, have intermittent network connectivity, etc.
// When we hit this many errors in succession, we stop.
const maxErrors = 30

func NewDiscoverer(id string, port int, extServer string) (*Discoverer, error) {
	local := &net.UDPAddr{IP: nil, Port: AnnouncementPort}
	conn, err := net.ListenUDP("udp", local)
	if err != nil {
		return nil, err
	}

	disc := &Discoverer{
		MyID:             id,
		ListenPort:       port,
		BroadcastIntv:    30 * time.Second,
		ExtBroadcastIntv: 1800 * time.Second,

		conn:      conn,
		registry:  make(map[string][]string),
		extServer: extServer,
	}

	go disc.recvAnnouncements()

	if disc.ListenPort > 0 {
		disc.localBroadcastTick = time.Tick(disc.BroadcastIntv)
		disc.forcedBroadcastTick = make(chan time.Time)
		go disc.sendAnnouncements()
	}
	if len(disc.extServer) > 0 {
		go disc.sendExtAnnouncements()
	}

	return disc, nil
}

func (d *Discoverer) sendAnnouncements() {
	var pkt = AnnounceV2{AnnouncementMagicV2, d.MyID, []Address{{nil, 22000}}}
	var buf = pkt.MarshalXDR()
	var errCounter = 0
	var err error

	for errCounter < maxErrors {
		for _, ipStr := range allBroadcasts() {
			var addrStr = ipStr + ":21025"

			remote, err := net.ResolveUDPAddr("udp4", addrStr)
			if err != nil {
				log.Printf("discover/external: %v; no external announcements", err)
				return
			}

			if Debug {
				fmt.Println("send announcement -> ", remote)
			}
			_, _, err = d.conn.WriteMsgUDP(buf, nil, remote)
			if err != nil {
				log.Println("discover/write: warning:", err)
				errCounter++
			} else {
				errCounter = 0
			}
		}

		select {
		case <-d.localBroadcastTick:
		case <-d.forcedBroadcastTick:
		}
	}
	log.Println("discover/write: local: stopping due to too many errors:", err)
}

func (d *Discoverer) sendExtAnnouncements() {
	remote, err := net.ResolveUDPAddr("udp", d.extServer)
	if err != nil {
		log.Printf("discover/external: %v; no external announcements", err)
		return
	}

	var pkt = AnnounceV2{AnnouncementMagicV2, d.MyID, []Address{{nil, 22000}}}
	var buf = pkt.MarshalXDR()
	var errCounter = 0

	for errCounter < maxErrors {
		if Debug {
			fmt.Println("send announcement -> ", remote)
		}
		_, _, err = d.conn.WriteMsgUDP(buf, nil, remote)
		if err != nil {
			log.Println("discover/write: warning:", err)
			errCounter++
		} else {
			errCounter = 0
		}
		time.Sleep(d.ExtBroadcastIntv)
	}
	log.Println("discover/write: %v: stopping due to too many errors:", remote, err)
}

func (d *Discoverer) recvAnnouncements() {
	var buf = make([]byte, 1024)
	var errCounter = 0
	var err error
	for errCounter < maxErrors {
		n, addr, err := d.conn.ReadFromUDP(buf)
		if err != nil {
			errCounter++
			time.Sleep(time.Second)
			continue
		}

		if Debug {
			log.Printf("read announcement:\n%s", hex.Dump(buf[:n]))
		}

		var pkt AnnounceV2
		err = pkt.UnmarshalXDR(buf[:n])
		if err != nil {
			errCounter++
			time.Sleep(time.Second)
			continue
		}

		if Debug {
			log.Printf("read announcement: %#v", pkt)
		}

		errCounter = 0

		if pkt.NodeID != d.MyID {
			var addrs []string
			for _, a := range pkt.Addresses {
				var nodeAddr string
				if len(a.IP) > 0 {
					nodeAddr = fmt.Sprintf("%s:%d", ipStr(a.IP), a.Port)
				} else {
					nodeAddr = fmt.Sprintf("%s:%d", addr.IP.String(), a.Port)
				}
				addrs = append(addrs, nodeAddr)
			}
			if Debug {
				log.Printf("register: %#v", addrs)
			}
			d.registryLock.Lock()
			_, seen := d.registry[pkt.NodeID]
			if !seen {
				fmt.Println("new node seen, forced announce")
				select {
				case d.forcedBroadcastTick <- time.Now():
				}
			}
			d.registry[pkt.NodeID] = addrs
			d.registryLock.Unlock()
		}
	}
	log.Println("discover/read: stopping due to too many errors:", err)
}

func (d *Discoverer) externalLookup(node string) []string {
	extIP, err := net.ResolveUDPAddr("udp", d.extServer)
	if err != nil {
		log.Printf("discover/external: %v; no external lookup", err)
		return nil
	}

	conn, err := net.DialUDP("udp", nil, extIP)
	if err != nil {
		log.Printf("discover/external: %v; no external lookup", err)
		return nil
	}
	defer conn.Close()

	err = conn.SetDeadline(time.Now().Add(5 * time.Second))
	if err != nil {
		log.Printf("discover/external: %v; no external lookup", err)
		return nil
	}

	buf := QueryV2{QueryMagicV2, node}.MarshalXDR()
	_, err = conn.Write(buf)
	if err != nil {
		log.Printf("discover/external: %v; no external lookup", err)
		return nil
	}
	buffers.Put(buf)

	buf = buffers.Get(256)
	defer buffers.Put(buf)

	n, err := conn.Read(buf)
	if err != nil {
		if err, ok := err.(net.Error); ok && err.Timeout() {
			// Expected if the server doesn't know about requested node ID
			return nil
		}
		log.Printf("discover/external/read: %v; no external lookup", err)
		return nil
	}

	if Debug {
		log.Printf("read external:\n%s", hex.Dump(buf[:n]))
	}

	var pkt AnnounceV2
	err = pkt.UnmarshalXDR(buf[:n])
	if err != nil {
		log.Println("discover/external/decode:", err)
		return nil
	}

	if Debug {
		log.Printf("read external: %#v", pkt)
	}

	var addrs []string
	for _, a := range pkt.Addresses {
		var nodeAddr string
		if len(a.IP) > 0 {
			nodeAddr = fmt.Sprintf("%s:%d", ipStr(a.IP), a.Port)
		}
		addrs = append(addrs, nodeAddr)
	}
	return addrs
}

func (d *Discoverer) Lookup(node string) []string {
	d.registryLock.Lock()
	addr, ok := d.registry[node]
	d.registryLock.Unlock()

	if ok {
		return addr
	} else if len(d.extServer) != 0 {
		// We might want to cache this, but not permanently so it needs some intelligence
		return d.externalLookup(node)
	}
	return nil
}

func ipStr(ip []byte) string {
	var f = "%d"
	var s = "."
	if len(ip) > 4 {
		f = "%x"
		s = ":"
	}
	var ss = make([]string, len(ip))
	for i := range ip {
		ss[i] = fmt.Sprintf(f, ip[i])
	}
	return strings.Join(ss, s)
}

func allBroadcasts() []string {
	var bcasts = make(map[string]bool)
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		return nil
	}

	for _, addr := range addrs {
		switch {
		case strings.HasPrefix(addr.String(), "127."):
			// Ignore v4 localhost

		case strings.Contains(addr.String(), ":"):
			// Ignore all v6, because we need link local multicast there which I haven't implemented

		default:
			if in, ok := addr.(*net.IPNet); ok {
				il := len(in.IP) - 1
				ml := len(in.Mask) - 1
				for i := range in.Mask {
					in.IP[il-i] = in.IP[il-i] | ^in.Mask[ml-i]
				}
				parts := strings.Split(in.String(), "/")
				bcasts[parts[0]] = true
			}
		}
	}

	var l []string
	for ip := range bcasts {
		l = append(l, ip)
	}
	return l
}
<|endoftext|>


<commit_before>package CloudForest

import (
	"math"
)

/*
NPTarget wraps a categorical feature for use approximate NP classification.
It uses an impurity measure derived from the seccond family presented in

"Comparison and Design of Neyman-Pearson Classiﬁers"
Clayton Scott,  October 2005

http://www.stat.rice.edu/~cscott/pubs/npdesign.pdf

N(f) = κ max((R0(f) − α), 0) + R1(f) − β.

Where α is the false positive constraint and k controls the cost of violating
this constraint and β is a constant we can ignore.
*/
type NPTarget struct {
	CatFeature
	Posi  int
	Alpha float64
	Kappa float64
}

//NewNPTarget creates a RefretTarget and initializes NPTarget.Costs to the proper length.
func NewNPTarget(f CatFeature, Pos string, Alpha, Kappa float64) *NPTarget {
	return &NPTarget{f, f.CatToNum(Pos), Alpha, Kappa}
}

/*
NPTarget.SplitImpurity is a version of Split Impurity that calls NPTarget.Impurity
*/
func (target *NPTarget) SplitImpurity(l *[]int, r *[]int, m *[]int, allocs *BestSplitAllocs) (impurityDecrease float64) {
	nl := float64(len(*l))
	nr := float64(len(*r))
	nm := 0.0

	impurityDecrease = nl * target.Impurity(l, allocs.LCounter)
	impurityDecrease += nr * target.Impurity(r, allocs.RCounter)
	if m != nil && len(*m) > 0 {
		nm = float64(len(*m))
		impurityDecrease += nm * target.Impurity(m, allocs.Counter)
	}

	impurityDecrease /= nl + nr + nm
	return
}

//UpdateSImpFromAllocs willl be called when splits are being built by moving cases from r to l as in learning from numerical variables.
//Here it just wraps SplitImpurity but it can be implemented to provide further optimization.
func (target *NPTarget) UpdateSImpFromAllocs(l *[]int, r *[]int, m *[]int, allocs *BestSplitAllocs, movedRtoL *[]int) (impurityDecrease float64) {
	return target.SplitImpurity(l, r, m, allocs)
}

//NPTarget.Impurity implements a simple regret function that finds the average cost of
//a set using the misclassification costs in NPTarget.Costs.
func (target *NPTarget) Impurity(cases *[]int, counter *[]int) (e float64) {

	var t, totalpos, totalneg int
	for _, c := range *cases {
		if target.IsMissing(c) == false {
			t++
			cat := target.Geti(c)
			if cat == target.Posi {
				totalpos++
			} else {
				totalneg++
			}
		}

	}

	if target.Posi == target.Modei(cases) {
		//False positive constraint
		e = target.Kappa * math.Max(float64(totalneg)/float64(t)-target.Alpha, 0)
	} else {
		//False negative rate
		e = float64(totalpos) / float64(t)
	}

	// e = float64(totalneg) * target.Kappa * math.Max(float64(totalneg)/float64(t)-target.Alpha, 0)
	// e += float64(totalpos) * float64(totalpos) / float64(t)
	// e /= float64(t)

	return
}
<commit_msg>Documentation for NP Target<commit_after>package CloudForest

import (
	"math"
)

/*
NPTarget wraps a categorical feature for use approximate NP classification.
It uses an impurity measure derived from the seccond family presented in

"Comparison and Design of Neyman-Pearson Classiﬁers"
Clayton Scott,  October 2005

http://www.stat.rice.edu/~cscott/pubs/npdesign.pdf

N(f) = κ max((R0(f) − α), 0) + R1(f) − β.

Where f is the classifer, R0 is the flase positive rate R1 is the false negative rate,
α is the false positive constraint and k controls the cost of violating
this constraint and β is a constant we can ignore as it subtracts out in diffrences.
*/
type NPTarget struct {
	CatFeature
	Posi  int
	Alpha float64
	Kappa float64
}

//NewNPTarget creates a NPTarget
func NewNPTarget(f CatFeature, Pos string, Alpha, Kappa float64) *NPTarget {
	return &NPTarget{f, f.CatToNum(Pos), Alpha, Kappa}
}

/*
NPTarget.SplitImpurity is a version of Split Impurity that calls NPTarget.Impurity
*/
func (target *NPTarget) SplitImpurity(l *[]int, r *[]int, m *[]int, allocs *BestSplitAllocs) (impurityDecrease float64) {
	nl := float64(len(*l))
	nr := float64(len(*r))
	nm := 0.0

	impurityDecrease = nl * target.Impurity(l, allocs.LCounter)
	impurityDecrease += nr * target.Impurity(r, allocs.RCounter)
	if m != nil && len(*m) > 0 {
		nm = float64(len(*m))
		impurityDecrease += nm * target.Impurity(m, allocs.Counter)
	}

	impurityDecrease /= nl + nr + nm
	return
}

//UpdateSImpFromAllocs willl be called when splits are being built by moving cases from r to l as in learning from numerical variables.
//Here it just wraps SplitImpurity but it can be implemented to provide further optimization.
func (target *NPTarget) UpdateSImpFromAllocs(l *[]int, r *[]int, m *[]int, allocs *BestSplitAllocs, movedRtoL *[]int) (impurityDecrease float64) {
	return target.SplitImpurity(l, r, m, allocs)
}

//NPTarget.Impurity implements an impurity that minimizes false negatives subject
//to a soft constrain on fale positives.
func (target *NPTarget) Impurity(cases *[]int, counter *[]int) (e float64) {

	var t, totalpos, totalneg int
	for _, c := range *cases {
		if target.IsMissing(c) == false {
			t++
			cat := target.Geti(c)
			if cat == target.Posi {
				totalpos++
			} else {
				totalneg++
			}
		}

	}

	if target.Posi == target.Modei(cases) {
		//False positive constraint
		e = target.Kappa * math.Max(float64(totalneg)/float64(t)-target.Alpha, 0)
	} else {
		//False negative rate
		e = float64(totalpos) / float64(t)
	}

	// e = float64(totalneg) * target.Kappa * math.Max(float64(totalneg)/float64(t)-target.Alpha, 0)
	// e += float64(totalpos) * float64(totalpos) / float64(t)
	// e /= float64(t)

	return
}
<|endoftext|>


<commit_before>package Common

import (
	"time"
)

// format a time.Time to string as 2006-01-02 15:04:05.999
func FormatTime(t time.Time) string {
	return t.Format("2006-01-02 15:04:05.999")
}

// format time.Now() use FormatTime
func FormatNow() string {
	return FormatTime(time.Now())
}

// parse a string as "2006-01-02 15:04:05.999" to time.Time
func ParseTime(s string) (time.Time, error) {
	return time.ParseInLocation("2006-01-02 15:04:05.999", s, time.Local)
}

// format a time.Time to number as 20060102150405999
func NumberTime(t time.Time) uint64 {
	y, m, d := t.Date()
	h, M, s := t.Clock()
	ms := t.Nanosecond() / 1000000
	return uint64(ms+s*1000+M*100000+h*10000000+d*1000000000) +
		uint64(m)*100000000000 + uint64(y)*10000000000000
}

// format time.Now() use NumberTime
func NumberNow() uint64 {
	return NumberTime(time.Now())
}

// parse a uint64 as 20060102150405999 to time.Time
func ParseNumber(t uint64) (time.Time, error) {
	ns := int((t % 1000) * 1000000)
	t /= 1000
	s := int(t % 100)
	t /= 100
	M := int(t % 100)
	t /= 100
	h := int(t % 100)
	t /= 100
	d := int(t % 100)
	t /= 100
	m := time.Month(t % 100)
	y := int(t / 100)

	return time.Date(y, m, d, h, M, s, ns, time.Local), nil
}
<commit_msg>add NumberUTC<commit_after>package Common

import (
	"time"
)

// format a time.Time to string as 2006-01-02 15:04:05.999
func FormatTime(t time.Time) string {
	return t.Format("2006-01-02 15:04:05.999")
}

// format time.Now() use FormatTime
func FormatNow() string {
	return FormatTime(time.Now())
}

// parse a string as "2006-01-02 15:04:05.999" to time.Time
func ParseTime(s string) (time.Time, error) {
	return time.ParseInLocation("2006-01-02 15:04:05.999", s, time.Local)
}

// format a time.Time to number as 20060102150405999
func NumberTime(t time.Time) uint64 {
	y, m, d := t.Date()
	h, M, s := t.Clock()
	ms := t.Nanosecond() / 1000000
	return uint64(ms+s*1000+M*100000+h*10000000+d*1000000000) +
		uint64(m)*100000000000 + uint64(y)*10000000000000
}

// format time.Now() use NumberTime
func NumberNow() uint64 {
	return NumberTime(time.Now())
}

// format time.Now().UTC() use NumberTime
func NumberUTC() uint64 {
	return NumberTime(time.Now().UTC())
}

// parse a uint64 as 20060102150405999 to time.Time
func ParseNumber(t uint64) (time.Time, error) {
	ns := int((t % 1000) * 1000000)
	t /= 1000
	s := int(t % 100)
	t /= 100
	M := int(t % 100)
	t /= 100
	h := int(t % 100)
	t /= 100
	d := int(t % 100)
	t /= 100
	m := time.Month(t % 100)
	y := int(t / 100)

	return time.Date(y, m, d, h, M, s, ns, time.Local), nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/hex"
	"fmt"
	"os"
)

const size = 4

func main() {

	if len(os.Args) < 3 || len(os.Args[1]) != size*2 || len(os.Args[2]) != size*2 {
		fmt.Fprintf(os.Stderr, "invalid argument(s)")
		os.Exit(1)
	}

	s1, err := hex.DecodeString(os.Args[1])
	if err != nil {
		fmt.Fprintf(os.Stderr, "error for %s: %s", os.Args[1], err)
		os.Exit(1)
	}

	s2, err := hex.DecodeString(os.Args[2])
	if err != nil {
		fmt.Fprintf(os.Stderr, "error for %s: %s", os.Args[2], err)
		os.Exit(1)
	}

	fmt.Printf("% x\n% x\n", s1, s2)
	for i := 0; i < size; i++ {
		fmt.Printf("%x ", s1[i]^s2[i])
	}
	fmt.Println("")

}
<commit_msg>Added draft for task 4.1<commit_after>package main

import (
	"encoding/hex"
	"fmt"
	"os"
)

const size = 4

func bitCount(x byte) int {
	num := 0
	for x != 0 {
		x = x & (x - 1)
		num++
	}
	return num
}

func main() {

	if len(os.Args) < 3 || len(os.Args[1]) != size*2 || len(os.Args[2]) != size*2 {
		fmt.Fprintf(os.Stderr, "invalid argument(s)")
		os.Exit(1)
	}

	s1, err := hex.DecodeString(os.Args[1])
	if err != nil {
		fmt.Fprintf(os.Stderr, "error for %s: %s", os.Args[1], err)
		os.Exit(1)
	}

	s2, err := hex.DecodeString(os.Args[2])
	if err != nil {
		fmt.Fprintf(os.Stderr, "error for %s: %s", os.Args[2], err)
		os.Exit(1)
	}

	var bits int
	fmt.Printf("% x\n% x\n", s1, s2)
	for i := 0; i < size; i++ {
		bits += bitCount(s1[i] ^ s2[i])
		fmt.Printf("%x ", s1[i]^s2[i])
	}
	fmt.Println("")
	fmt.Println(bits)

}
<|endoftext|>


<commit_before>package meta

import (
	"io"
	"net"
)

// proxy brokers a connection from src to dst
func proxy(dst, src *net.TCPConn) error {
	// channels to wait on the close event for each connection
	serverClosed := make(chan struct{}, 1)
	clientClosed := make(chan struct{}, 1)
	errors := make(chan error, 1)

	go broker(dst, src, clientClosed, errors)
	go broker(src, dst, serverClosed, errors)

	// wait for one half of the proxy to exit, then trigger a shutdown of the
	// other half by calling CloseRead(). This will break the read loop in the
	// broker and allow us to fully close the connection cleanly without a
	// "use of closed network connection" error.
	var waitFor chan struct{}
	select {
	case <-clientClosed:
		// the client closed first and any more packets from the server aren't
		// useful, so we can optionally SetLinger(0) here to recycle the port
		// faster.
		dst.SetLinger(0)
		dst.CloseRead()
		waitFor = serverClosed
	case <-serverClosed:
		src.CloseRead()
		waitFor = clientClosed
	case err := <-errors:
		src.CloseRead()
		dst.SetLinger(0)
		dst.CloseRead()
		return err
	}

	// Wait for the other connection to close.
	<-waitFor
	return nil
}

// This does the actual data transfer.
// The broker only closes the Read side.
func broker(dst, src net.Conn, srcClosed chan struct{}, errors chan error) {
	// We can handle errors in a finer-grained manner by inlining io.Copy (it's
	// simple, and we drop the ReaderFrom or WriterTo checks for
	// net.Conn->net.Conn transfers, which aren't needed). This would also let
	// us adjust buffersize.
	_, err := io.Copy(dst, src)

	if err != nil {
		errors <- err
	}
	if err := src.Close(); err != nil {
		errors <- err
	}
	srcClosed <- struct{}{}
}
<commit_msg>fix TestCluster_OpenRaft is timeout #4853<commit_after>package meta

import (
	"io"
	"net"
)

// proxy brokers a connection from src to dst
func proxy(dst, src *net.TCPConn) error {
	// channels to wait on the close event for each connection
	serverClosed := make(chan struct{}, 1)
	clientClosed := make(chan struct{}, 1)
	errors := make(chan error, 2)

	go broker(dst, src, clientClosed, errors)
	go broker(src, dst, serverClosed, errors)

	// wait for one half of the proxy to exit, then trigger a shutdown of the
	// other half by calling CloseRead(). This will break the read loop in the
	// broker and allow us to fully close the connection cleanly without a
	// "use of closed network connection" error.
	var waitFor chan struct{}
	select {
	case <-clientClosed:
		// the client closed first and any more packets from the server aren't
		// useful, so we can optionally SetLinger(0) here to recycle the port
		// faster.
		dst.SetLinger(0)
		dst.Close()
		waitFor = serverClosed
	case <-serverClosed:
		src.Close()
		waitFor = clientClosed
	case err := <-errors:
		src.Close()
		dst.SetLinger(0)
		dst.Close()
		return err
	}

	// Wait for the other connection to close.
	<-waitFor
	return nil
}

// This does the actual data transfer.
// The broker only closes the Read side.
func broker(dst, src net.Conn, srcClosed chan struct{}, errors chan error) {
	// We can handle errors in a finer-grained manner by inlining io.Copy (it's
	// simple, and we drop the ReaderFrom or WriterTo checks for
	// net.Conn->net.Conn transfers, which aren't needed). This would also let
	// us adjust buffersize.
	_, err := io.Copy(dst, src)

	if err != nil {
		errors <- err
	}
	if err := src.Close(); err != nil {
		errors <- err
	}
	srcClosed <- struct{}{}
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package main

import (
	"log"
	"os"
	"sort"
	"strings"
	"text/template"

	"golang.org/x/net/idna"

	"github.com/mvdan/xurls"
)

const path = "regex.go"

var regexTmpl = template.Must(template.New("regex").Parse(`// Generated by regexgen

package xurls

const ({{ range $key, $value := . }}
	{{$key}} = ` + "`" + `{{$value}}` + "`" + `{{end}}
)
`))

func writeRegex(tlds []string) error {
	allTldsSet := make(map[string]struct{})
	add := func(tld string) {
		if _, e := allTldsSet[tld]; e {
			log.Fatalf("Duplicate TLD: %s", tld)
		}
		allTldsSet[tld] = struct{}{}
	}
	for _, tldlist := range [...][]string{tlds, xurls.PseudoTLDs} {
		for _, tld := range tldlist {
			add(tld)
			asciiTld, err := idna.ToASCII(tld)
			if err != nil {
				return err
			}
			if asciiTld != tld {
				add(asciiTld)
			}
		}
	}
	var allTlds []string
	for tld := range allTldsSet {
		allTlds = append(allTlds, tld)
	}
	sort.Strings(allTlds)
	f, err := os.Create(path)
	if err != nil {
		return err
	}
	defer f.Close()
	return regexTmpl.Execute(f, map[string]string{
		"gtld       ": `(?i)(` + strings.Join(allTlds, `|`) + `)(?-i)`,
		"otherScheme": `(?i)(` + strings.Join(xurls.SchemesNoAuthority, `|`) + `)(?-i):`,
	})
}

func main() {
	log.Printf("Generating %s...", path)
	if err := writeRegex(xurls.TLDs); err != nil {
		log.Fatalf("Could not write %s: %v", path, err)
	}
}
<commit_msg>Make use of easier to read templates<commit_after>// Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package main

import (
	"log"
	"os"
	"sort"
	"strings"
	"text/template"

	"golang.org/x/net/idna"

	"github.com/mvdan/xurls"
)

const path = "regex.go"

var regexTmpl = template.Must(template.New("regex").Parse(`// Generated by regexgen

package xurls

const (
{{- range $key, $value := . }}
	{{$key}} = ` + "`" + `{{$value}}` + "`" + `
{{- end}}
)
`))

func writeRegex(tlds []string) error {
	allTldsSet := make(map[string]struct{})
	add := func(tld string) {
		if _, e := allTldsSet[tld]; e {
			log.Fatalf("Duplicate TLD: %s", tld)
		}
		allTldsSet[tld] = struct{}{}
	}
	for _, tldlist := range [...][]string{tlds, xurls.PseudoTLDs} {
		for _, tld := range tldlist {
			add(tld)
			asciiTld, err := idna.ToASCII(tld)
			if err != nil {
				return err
			}
			if asciiTld != tld {
				add(asciiTld)
			}
		}
	}
	var allTlds []string
	for tld := range allTldsSet {
		allTlds = append(allTlds, tld)
	}
	sort.Strings(allTlds)
	f, err := os.Create(path)
	if err != nil {
		return err
	}
	defer f.Close()
	return regexTmpl.Execute(f, map[string]string{
		"gtld       ": `(?i)(` + strings.Join(allTlds, `|`) + `)(?-i)`,
		"otherScheme": `(?i)(` + strings.Join(xurls.SchemesNoAuthority, `|`) + `)(?-i):`,
	})
}

func main() {
	log.Printf("Generating %s...", path)
	if err := writeRegex(xurls.TLDs); err != nil {
		log.Fatalf("Could not write %s: %v", path, err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"net/http"
	"strings"
	"time"

	"github.com/litl/galaxy/log"
	"github.com/litl/galaxy/registry"
)

type BackendConfig struct {
	Name      string `json:"name"`
	Addr      string `json:"address"`
	CheckAddr string `json:"check_address"`
	Weight    int    `json:"weight"`
}
type ServiceConfig struct {
	Name          string          `json:"name"`
	Addr          string          `json:"address"`
	Backends      []BackendConfig `json:"backends"`
	Balance       string          `json:"balance"`
	CheckInterval int             `json:"check_interval"`
	Fall          int             `json:"fall"`
	Rise          int             `json:"rise"`
	ClientTimeout int             `json:"client_timeout"`
	ServerTimeout int             `json:"server_timeout"`
	DialTimeout   int             `json:"connect_timeout"`
}

func RunShuttle(shuttleAddr string) {
	shuttleAddr = "http://" + shuttleAddr
	log.Printf("Updating shuttle at %s", shuttleAddr)

	// give us some way to fail if shuttle gets locked up
	transport := &http.Transport{ResponseHeaderTimeout: 2 * time.Second}
	httpClient := &http.Client{Transport: transport}

	for {
		// These are declared up here due to the goto error handling.
		// We need a map to populate the services,
		// and a slice to serialize to a JSON array.
		svcMap := make(map[string]*ServiceConfig)
		var reqJSON []byte
		var resp *http.Response
		var allRegs []registry.ServiceRegistration
		var allApps []registry.ServiceConfig
		var err error

		allRegs, err = serviceRegistry.ListRegistrations()
		if err != nil {
			log.Println("Error getting registrations:", err)
			goto SLEEP
		}

		// get all registered applications so we know what ports to listen on
		allApps, err = serviceRegistry.ListApps("*")
		if err != nil {
			log.Println("Error listing apps:", err)
			goto SLEEP
		}

		// Make a Service config to listen for every service in our env
		for _, cfg := range allApps {
			service, ok := svcMap[cfg.Name]
			if !ok {
				// TODO: make some of this configurable
				service = &ServiceConfig{
					Name:          cfg.Name,
					Addr:          "127.0.0.1:" + cfg.EnvGet("PORT"),
					CheckInterval: 2000,
					Fall:          2,
					Rise:          3,
					DialTimeout:   2000,
				}
				svcMap[cfg.Name] = service
				log.Debugf("updating shuttle service %+v", service)
			}
		}

		// Add the all the backends we can find to the services
		for _, reg := range allRegs {
			pathParts := strings.Split(reg.Path, "/")
			if len(pathParts) < 5 {
				log.Printf("Error, bad registration path: %s", pathParts)
				continue
			}

			hostName, svcName := pathParts[3], pathParts[4]

			service, ok := svcMap[svcName]
			if !ok {
				log.Printf("Found registration for unknown service %s:%s", service, reg)
				continue
			}

			backend := BackendConfig{
				Name: hostName,
				Addr: reg.ExternalIP + ":" + reg.ExternalPort,
			}
			backend.CheckAddr = backend.Addr
			log.Debugf("updating shuttle backend %+v", backend)

			service.Backends = append(service.Backends, backend)
		}

		// POST each of the Services to shuttle
		for name, service := range svcMap {
			reqJSON, err = json.Marshal(service)
			if err != nil {
				log.Println("ERROR serializing services:", err)
				continue
			}

			resp, err = httpClient.Post(shuttleAddr+"/"+name, "application/json", bytes.NewReader(reqJSON))
			if err != nil {
				log.Println("ERROR updating shuttle config:", err)
				continue
			}

			if resp.StatusCode != http.StatusOK {
				log.Printf("ERROR: recieved %s from shuttle", resp.Status)
			}
		}

	SLEEP:
		// TODO: make update interval a flag or config option
		time.Sleep(5 * time.Second)
	}
}
<commit_msg>Clean up discovery/shuttle poll loop<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"net/http"
	"strings"
	"time"

	"github.com/litl/galaxy/log"
)

type BackendConfig struct {
	Name      string `json:"name"`
	Addr      string `json:"address"`
	CheckAddr string `json:"check_address"`
	Weight    int    `json:"weight"`
}
type ServiceConfig struct {
	Name          string          `json:"name"`
	Addr          string          `json:"address"`
	Backends      []BackendConfig `json:"backends"`
	Balance       string          `json:"balance"`
	CheckInterval int             `json:"check_interval"`
	Fall          int             `json:"fall"`
	Rise          int             `json:"rise"`
	ClientTimeout int             `json:"client_timeout"`
	ServerTimeout int             `json:"server_timeout"`
	DialTimeout   int             `json:"connect_timeout"`
}

// build our shuttle config from the current state of registered services.
func buildConfig() (map[string]*ServiceConfig, error) {
	svcMap := make(map[string]*ServiceConfig)

	allRegs, err := serviceRegistry.ListRegistrations()
	if err != nil {
		log.Println("Error getting registrations:", err)
		return nil, err
	}

	// get all registered applications so we know what ports to listen on
	allApps, err := serviceRegistry.ListApps("*")
	if err != nil {
		log.Println("Error listing apps:", err)
		return nil, err
	}

	// Make a Service config to listen for every service in our env
	for _, cfg := range allApps {
		service, ok := svcMap[cfg.Name]
		if !ok {
			// TODO: make some of this configurable
			service = &ServiceConfig{
				Name:          cfg.Name,
				Addr:          "127.0.0.1:" + cfg.EnvGet("PORT"),
				CheckInterval: 2000,
				Fall:          2,
				Rise:          3,
				DialTimeout:   2000,
			}
			svcMap[cfg.Name] = service
			log.Debugf("updating shuttle service %+v", service)
		}
	}

	// Add the all the backends we can find to the services
	for _, reg := range allRegs {
		pathParts := strings.Split(reg.Path, "/")
		if len(pathParts) < 5 {
			log.Printf("Error, bad registration path: %s", pathParts)
			continue
		}

		hostName, svcName := pathParts[3], pathParts[4]

		service, ok := svcMap[svcName]
		if !ok {
			log.Printf("Found registration for unknown service %s:%s", service, reg)
			continue
		}

		backend := BackendConfig{
			Name: hostName,
			Addr: reg.ExternalIP + ":" + reg.ExternalPort,
		}
		backend.CheckAddr = backend.Addr
		log.Debugf("updating shuttle backend %+v", backend)

		service.Backends = append(service.Backends, backend)
	}

	return svcMap, nil
}

func RunShuttle(shuttleAddr string) {
	shuttleAddr = "http://" + shuttleAddr
	log.Printf("Updating shuttle at %s", shuttleAddr)

	// give us some way to fail if shuttle gets locked up
	transport := &http.Transport{ResponseHeaderTimeout: 2 * time.Second}
	httpClient := &http.Client{Transport: transport}

	for {
		svcMap, err := buildConfig()
		if err != nil {
			goto SLEEP
		}

		for name, service := range svcMap {
			reqJSON, err := json.Marshal(service)
			if err != nil {
				log.Println("ERROR serializing services:", err)
				continue
			}

			resp, err := httpClient.Post(shuttleAddr+"/"+name, "application/json", bytes.NewReader(reqJSON))
			if err != nil {
				log.Println("ERROR updating shuttle config:", err)
				continue
			}

			if resp.StatusCode != http.StatusOK {
				log.Printf("ERROR: recieved %s from shuttle", resp.Status)
			}
		}

	SLEEP:
		// TODO: make update interval a flag or config option
		time.Sleep(5 * time.Second)
	}
}
<|endoftext|>


<commit_before>package mpb

import (
	"bytes"
	"testing"
)

func TestDraw(t *testing.T) {
	// key is termWidth
	testSuite := map[int]map[string]struct {
		total, current int64
		barWidth       int
		barRefill      *refill
		want           string
	}{
		100: {
			"t,c,bw{100,100,0}": {
				total:    100,
				current:  0,
				barWidth: 100,
				want:     "[--------------------------------------------------------------------------------------------------]",
			},
			"t,c,bw{100,1,100}": {
				total:    100,
				current:  1,
				barWidth: 100,
				want:     "[>-------------------------------------------------------------------------------------------------]",
			},
			"t,c,bw{100,40,100}": {
				total:    100,
				current:  40,
				barWidth: 100,
				want:     "[======================================>-----------------------------------------------------------]",
			},
			"t,c,bw{100,40,100}refill{'+', 32}": {
				total:     100,
				current:   40,
				barWidth:  100,
				barRefill: &refill{'+', 32},
				want:      "[+++++++++++++++++++++++++++++++=======>-----------------------------------------------------------]",
			},
			"t,c,bw{100,99,100}": {
				total:    100,
				current:  99,
				barWidth: 100,
				want:     "[================================================================================================>-]",
			},
			"t,c,bw{100,100,100}": {
				total:    100,
				current:  100,
				barWidth: 100,
				want:     "[==================================================================================================]",
			},
		},
		2: {
			"t,c,bw{0,0,100}": {
				barWidth: 100,
				want:     "[]",
			},
			"t,c,bw{60,20,80}": {
				total:    60,
				current:  20,
				barWidth: 80,
				want:     "[]",
			},
		},
		3: {
			"t,c,bw{100,20,100}": {
				total:    100,
				current:  20,
				barWidth: 100,
				want:     "[-]",
			},
			"t,c,bw{100,98,100}": {
				total:    100,
				current:  98,
				barWidth: 100,
				want:     "[=]",
			},
			"t,c,bw{100,100,100}": {
				total:    100,
				current:  100,
				barWidth: 100,
				want:     "[=]",
			},
		},
		5: {
			"t,c,bw{100,20,100}": {
				total:    100,
				current:  20,
				barWidth: 100,
				want:     "[>--]",
			},
			"t,c,bw{100,98,100}": {
				total:    100,
				current:  98,
				barWidth: 100,
				want:     "[===]",
			},
			"t,c,bw{100,100,100}": {
				total:    100,
				current:  100,
				barWidth: 100,
				want:     "[===]",
			},
		},
		6: {
			"t,c,bw{100,20,100}": {
				total:    100,
				current:  20,
				barWidth: 100,
				want:     "[>---]",
			},
			"t,c,bw{100,98,100}": {
				total:    100,
				current:  98,
				barWidth: 100,
				want:     "[====]",
			},
			"t,c,bw{100,100,100}": {
				total:    100,
				current:  100,
				barWidth: 100,
				want:     "[====]",
			},
		},
		20: {
			"t,c,bw{100,20,100}": {
				total:    100,
				current:  20,
				barWidth: 100,
				want:     "[===>--------------]",
			},
			"t,c,bw{100,60,100}": {
				total:    100,
				current:  60,
				barWidth: 100,
				want:     "[==========>-------]",
			},
			"t,c,bw{100,98,100}": {
				total:    100,
				current:  98,
				barWidth: 100,
				want:     "[==================]",
			},
			"t,c,bw{100,100,100}": {
				total:    100,
				current:  100,
				barWidth: 100,
				want:     "[==================]",
			},
		},
		50: {
			"t,c,bw{100,20,100}": {
				total:    100,
				current:  20,
				barWidth: 100,
				want:     "[=========>--------------------------------------]",
			},
			"t,c,bw{100,60,100}": {
				total:    100,
				current:  60,
				barWidth: 100,
				want:     "[============================>-------------------]",
			},
			"t,c,bw{100,98,100}": {
				total:    100,
				current:  98,
				barWidth: 100,
				want:     "[==============================================>-]",
			},
			"t,c,bw{100,100,100}": {
				total:    100,
				current:  100,
				barWidth: 100,
				want:     "[================================================]",
			},
		},
	}

	prependWs := newWidthSyncer(nil, 1, 0)
	appendWs := newWidthSyncer(nil, 1, 0)
	var temp bytes.Buffer
	for termWidth, cases := range testSuite {
		for name, tc := range cases {
			s := newTestState()
			s.width = tc.barWidth
			s.total = tc.total
			s.current = tc.current
			if tc.barRefill != nil {
				s.refill = tc.barRefill
			}
			temp.Reset()
			temp.ReadFrom(s.draw(termWidth, prependWs, appendWs))
			got := temp.String()
			if got != tc.want+"\n" {
				t.Errorf("termWidth %d; %s: want: %s %d, got: %s %d\n", termWidth, name, tc.want+"\n", len(tc.want), got, len(got))
			}
		}
	}
}

func newTestState() *bState {
	s := &bState{
		trimLeftSpace:  true,
		trimRightSpace: true,
		bufP:           new(bytes.Buffer),
		bufB:           new(bytes.Buffer),
		bufA:           new(bytes.Buffer),
	}
	s.runes = strToBarRunes("[=>-]")
	return s
}
<commit_msg>Refactoring draw test<commit_after>package mpb

import (
	"bytes"
	"testing"
)

func TestDraw(t *testing.T) {
	// key is termWidth
	testSuite := map[int]map[string]struct {
		total, current int64
		barWidth       int
		barRefill      *refill
		want           string
	}{
		100: {
			"t,c,bw{100,100,0}": {
				total:    100,
				current:  0,
				barWidth: 100,
				want:     "[--------------------------------------------------------------------------------------------------]",
			},
			"t,c,bw{100,1,100}": {
				total:    100,
				current:  1,
				barWidth: 100,
				want:     "[>-------------------------------------------------------------------------------------------------]",
			},
			"t,c,bw{100,40,100}": {
				total:    100,
				current:  40,
				barWidth: 100,
				want:     "[======================================>-----------------------------------------------------------]",
			},
			"t,c,bw{100,40,100}refill{'+', 32}": {
				total:     100,
				current:   40,
				barWidth:  100,
				barRefill: &refill{'+', 32},
				want:      "[+++++++++++++++++++++++++++++++=======>-----------------------------------------------------------]",
			},
			"t,c,bw{100,99,100}": {
				total:    100,
				current:  99,
				barWidth: 100,
				want:     "[================================================================================================>-]",
			},
			"t,c,bw{100,100,100}": {
				total:    100,
				current:  100,
				barWidth: 100,
				want:     "[==================================================================================================]",
			},
		},
		2: {
			"t,c,bw{0,0,100}": {
				barWidth: 100,
				want:     "[]",
			},
			"t,c,bw{60,20,80}": {
				total:    60,
				current:  20,
				barWidth: 80,
				want:     "[]",
			},
		},
		3: {
			"t,c,bw{100,20,100}": {
				total:    100,
				current:  20,
				barWidth: 100,
				want:     "[-]",
			},
			"t,c,bw{100,98,100}": {
				total:    100,
				current:  98,
				barWidth: 100,
				want:     "[=]",
			},
			"t,c,bw{100,100,100}": {
				total:    100,
				current:  100,
				barWidth: 100,
				want:     "[=]",
			},
		},
		5: {
			"t,c,bw{100,20,100}": {
				total:    100,
				current:  20,
				barWidth: 100,
				want:     "[>--]",
			},
			"t,c,bw{100,98,100}": {
				total:    100,
				current:  98,
				barWidth: 100,
				want:     "[===]",
			},
			"t,c,bw{100,100,100}": {
				total:    100,
				current:  100,
				barWidth: 100,
				want:     "[===]",
			},
		},
		6: {
			"t,c,bw{100,20,100}": {
				total:    100,
				current:  20,
				barWidth: 100,
				want:     "[>---]",
			},
			"t,c,bw{100,98,100}": {
				total:    100,
				current:  98,
				barWidth: 100,
				want:     "[====]",
			},
			"t,c,bw{100,100,100}": {
				total:    100,
				current:  100,
				barWidth: 100,
				want:     "[====]",
			},
		},
		20: {
			"t,c,bw{100,20,100}": {
				total:    100,
				current:  20,
				barWidth: 100,
				want:     "[===>--------------]",
			},
			"t,c,bw{100,60,100}": {
				total:    100,
				current:  60,
				barWidth: 100,
				want:     "[==========>-------]",
			},
			"t,c,bw{100,98,100}": {
				total:    100,
				current:  98,
				barWidth: 100,
				want:     "[==================]",
			},
			"t,c,bw{100,100,100}": {
				total:    100,
				current:  100,
				barWidth: 100,
				want:     "[==================]",
			},
		},
		50: {
			"t,c,bw{100,20,100}": {
				total:    100,
				current:  20,
				barWidth: 100,
				want:     "[=========>--------------------------------------]",
			},
			"t,c,bw{100,60,100}": {
				total:    100,
				current:  60,
				barWidth: 100,
				want:     "[============================>-------------------]",
			},
			"t,c,bw{100,98,100}": {
				total:    100,
				current:  98,
				barWidth: 100,
				want:     "[==============================================>-]",
			},
			"t,c,bw{100,100,100}": {
				total:    100,
				current:  100,
				barWidth: 100,
				want:     "[================================================]",
			},
		},
	}

	prependWs := newWidthSyncer(nil, 1, 0)
	appendWs := newWidthSyncer(nil, 1, 0)
	var tmpBuf bytes.Buffer
	for termWidth, cases := range testSuite {
		for name, tc := range cases {
			s := newTestState()
			s.width = tc.barWidth
			s.total = tc.total
			s.current = tc.current
			if tc.barRefill != nil {
				s.refill = tc.barRefill
			}
			tmpBuf.Reset()
			tmpBuf.ReadFrom(s.draw(termWidth, prependWs, appendWs))
			got := tmpBuf.String()
			want := tc.want + "\n"
			if got != want {
				t.Errorf("termWidth %d; %s: want: %s %d, got: %s %d\n", termWidth, name, want, len(want), got, len(got))
			}
		}
	}
}

func newTestState() *bState {
	s := &bState{
		trimLeftSpace:  true,
		trimRightSpace: true,
		bufP:           new(bytes.Buffer),
		bufB:           new(bytes.Buffer),
		bufA:           new(bytes.Buffer),
	}
	s.runes = strToBarRunes("[=>-]")
	return s
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"net"
	"os/exec"
	"testing"

	"github.com/docker/docker/daemon"
)

func TestNetworkNat(t *testing.T) {
	iface, err := net.InterfaceByName("eth0")
	if err != nil {
		t.Skip("Test not running with `make test`. Interface eth0 not found: %s", err)
	}

	ifaceAddrs, err := iface.Addrs()
	if err != nil || len(ifaceAddrs) == 0 {
		t.Fatalf("Error retrieving addresses for eth0: %v (%d addresses)", err, len(ifaceAddrs))
	}

	ifaceIp, _, err := net.ParseCIDR(ifaceAddrs[0].String())
	if err != nil {
		t.Fatalf("Error retrieving the up for eth0: %s", err)
	}

	runCmd := exec.Command(dockerBinary, "run", "-d", "-p", "8080", "busybox", "nc", "-lp", "8080")
	out, _, err := runCommandWithOutput(runCmd)
	errorOut(err, t, fmt.Sprintf("run1 failed with errors: %v (%s)", err, out))

	cleanedContainerID := stripTrailingCharacters(out)

	inspectCmd := exec.Command(dockerBinary, "inspect", cleanedContainerID)
	inspectOut, _, err := runCommandWithOutput(inspectCmd)
	errorOut(err, t, fmt.Sprintf("out should've been a container id: %v %v", inspectOut, err))

	containers := []*daemon.Container{}
	if err := json.Unmarshal([]byte(inspectOut), &containers); err != nil {
		t.Fatalf("Error inspecting the container: %s", err)
	}
	if len(containers) != 1 {
		t.Fatalf("Unepexted container count. Expected 0, recieved: %d", len(containers))
	}

	port8080, exists := containers[0].NetworkSettings.Ports["8080/tcp"]
	if !exists || len(port8080) == 0 {
		t.Fatal("Port 8080/tcp not found in NetworkSettings")
	}

	runCmd = exec.Command(dockerBinary, "run", "-p", "8080", "busybox", "sh", "-c", fmt.Sprintf("echo hello world | nc -w 30 %s %s", ifaceIp, port8080[0].HostPort))
	out, _, err = runCommandWithOutput(runCmd)
	errorOut(err, t, fmt.Sprintf("run2 failed with errors: %v (%s)", err, out))

	runCmd = exec.Command(dockerBinary, "logs", cleanedContainerID)
	out, _, err = runCommandWithOutput(runCmd)
	errorOut(err, t, fmt.Sprintf("failed to retrieve logs for container: %v %v", cleanedContainerID, err))

	if expected := "hello world\n"; out != expected {
		t.Fatalf("Unexpected output. Expected: %s, recieved: -->%s<--", expected, out)
	}

	killCmd := exec.Command(dockerBinary, "kill", cleanedContainerID)
	out, _, err = runCommandWithOutput(killCmd)
	errorOut(err, t, fmt.Sprintf("failed to kill container: %v %v", out, err))
	deleteAllContainers()

	logDone("network - make sure nat works through the host")
}
<commit_msg>Make nat test less racy and accurate<commit_after>package main

import (
	"fmt"
	"net"
	"os/exec"
	"strings"
	"testing"
)

func TestNetworkNat(t *testing.T) {
	iface, err := net.InterfaceByName("eth0")
	if err != nil {
		t.Skip("Test not running with `make test`. Interface eth0 not found: %s", err)
	}

	ifaceAddrs, err := iface.Addrs()
	if err != nil || len(ifaceAddrs) == 0 {
		t.Fatalf("Error retrieving addresses for eth0: %v (%d addresses)", err, len(ifaceAddrs))
	}

	ifaceIp, _, err := net.ParseCIDR(ifaceAddrs[0].String())
	if err != nil {
		t.Fatalf("Error retrieving the up for eth0: %s", err)
	}

	runCmd := exec.Command(dockerBinary, "run", "-dt", "-p", "8080:8080", "busybox", "nc", "-lp", "8080")
	out, _, err := runCommandWithOutput(runCmd)
	errorOut(err, t, fmt.Sprintf("run1 failed with errors: %v (%s)", err, out))

	cleanedContainerID := stripTrailingCharacters(out)

	runCmd = exec.Command(dockerBinary, "run", "busybox", "sh", "-c", fmt.Sprintf("echo hello world | nc -w 30 %s 8080", ifaceIp))
	out, _, err = runCommandWithOutput(runCmd)
	errorOut(err, t, fmt.Sprintf("run2 failed with errors: %v (%s)", err, out))

	runCmd = exec.Command(dockerBinary, "logs", cleanedContainerID)
	out, _, err = runCommandWithOutput(runCmd)
	errorOut(err, t, fmt.Sprintf("failed to retrieve logs for container: %v %v", cleanedContainerID, err))
	out = strings.Trim(out, "\r\n")

	if expected := "hello world"; out != expected {
		t.Fatalf("Unexpected output. Expected: %q, received: %q for iface %s", expected, out, ifaceIp)
	}

	killCmd := exec.Command(dockerBinary, "kill", cleanedContainerID)
	out, _, err = runCommandWithOutput(killCmd)
	errorOut(err, t, fmt.Sprintf("failed to kill container: %v %v", out, err))
	deleteAllContainers()

	logDone("network - make sure nat works through the host")
}
<|endoftext|>


<commit_before>package metafora

import (
	"math"
	"math/rand"
	"time"
)

const (
	// Default threshold is 120% of cluster average
	defaultThreshold float64 = 1.2
)

// NoDelay is simply the zero value for time and meant to be a more meaningful
// value for CanClaim methods to return instead of initializing a new empty
// time struct.
var NoDelay = time.Time{}

// BalancerContext is a limited interface exposed to Balancers from the
// Consumer for access to limited Consumer state.
type BalancerContext interface {
	// Tasks returns a sorted list of task IDs run by this Consumer. The Consumer
	// stops task manipulations during claiming and balancing, so the list will
	// be accurate unless a task naturally completes.
	Tasks() []Task
}

// Balancer is the core task balancing interface. Without a master Metafora
// clusters are cooperatively balanced -- meaning each node needs to know how
// to balance itself.
type Balancer interface {
	// Init is called once and only once before any other Balancer methods are
	// called. The context argument is meant to expose functionality that might
	// be useful for CanClaim and Balance implementations.
	Init(BalancerContext)

	// CanClaim should return true if the consumer should accept a task.
	//
	// When denying a claim by returning false, CanClaim should return the time
	// at which to reconsider the task for claiming.
	CanClaim(taskID string) (ignoreUntil time.Time, claim bool)

	// Balance should return the list of Task IDs that should be released. The
	// criteria used to determine which tasks should be released is left up to
	// the implementation.
	Balance() (release []string)
}

// DumbBalancer is the simplest possible balancer implementation which simply
// accepts all tasks. Since it has no state a single global instance exists.
var DumbBalancer = dumbBalancer{}

type dumbBalancer struct{}

// Init does nothing.
func (dumbBalancer) Init(BalancerContext) {}

// CanClaim always returns true.
func (dumbBalancer) CanClaim(string) (time.Time, bool) { return NoDelay, true }

// Balance never returns any tasks to balance.
func (dumbBalancer) Balance() []string { return nil }

// Provides information about the cluster to be used by FairBalancer
type ClusterState interface {
	// Provide the current number of jobs
	NodeTaskCount() (map[string]int, error)
}

// NewDefaultFairBalancer creates a new FairBalancer but requires a
// ClusterState implementation to gain more information about the cluster than
// BalancerContext provides.
func NewDefaultFairBalancer(nodeid string, cs ClusterState) Balancer {
	return NewDefaultFairBalancerWithThreshold(nodeid, cs, defaultThreshold)
}

// NewDefaultFairBalancerWithThreshold allows callers to override
// FairBalancer's default 120% task load release threshold.
func NewDefaultFairBalancerWithThreshold(nodeid string, cs ClusterState, threshold float64) Balancer {
	return &FairBalancer{
		nodeid:           nodeid,
		clusterstate:     cs,
		releaseThreshold: threshold,
	}
}

// An implementation of Balancer which attempts to randomly release tasks in
// the case when the count of those currently running on this node is greater
// than some percentage of the cluster average (default 120%).
//
// This balancer will claim all tasks which were not released on the last call
// to Balance.
type FairBalancer struct {
	nodeid string

	bc           BalancerContext
	clusterstate ClusterState

	releaseThreshold float64
	delay            time.Duration
}

func (e *FairBalancer) Init(s BalancerContext) {
	e.bc = s
}

// CanClaim will claim any task if this node wasn't over the task threshold
// during the last rebalance. If it was over the threshold claims will be
// delayed proportionally.
func (e *FairBalancer) CanClaim(taskid string) (time.Time, bool) {
	if e.delay == 0 {
		return NoDelay, true
	}
	return time.Now().Add(e.delay), false
}

// Balance releases tasks if this node has 120% more tasks than the average
// node in the cluster.
func (e *FairBalancer) Balance() []string {
	nodetasks := e.bc.Tasks()

	// Reset delay
	e.delay = 0

	// If local tasks <= 1 this node should never rebalance
	if len(nodetasks) < 2 {
		return nil
	}

	current, err := e.clusterstate.NodeTaskCount()
	if err != nil {
		Warnf("Error retrieving cluster state: %v", err)
		return nil
	}

	shouldrelease := current[e.nodeid] - e.desiredCount(current)
	if shouldrelease < 1 {
		return nil
	}

	releasetasks := make([]string, 0, shouldrelease)
	releaseset := make(map[string]struct{}, shouldrelease)

	random := rand.New(rand.NewSource(time.Now().UnixNano()))
	for len(releasetasks) < shouldrelease {
		tid := nodetasks[random.Intn(len(nodetasks))].ID()
		if _, ok := releaseset[tid]; !ok {
			releasetasks = append(releasetasks, tid)
			releaseset[tid] = struct{}{}
		}
	}

	e.delay = time.Duration(len(releasetasks)) * time.Second
	return releasetasks
}

// Retrieve the desired maximum count, based on current cluster state
func (e *FairBalancer) desiredCount(current map[string]int) int {
	total := 0
	for _, c := range current {
		total += c
	}

	avg := 0
	if len(current) > 0 {
		avg = total / len(current)
	}

	return int(math.Ceil(float64(avg) * e.releaseThreshold))
}
<commit_msg>Fix bad behavior where fair balancer would spin after releasing tasks<commit_after>package metafora

import (
	"math"
	"math/rand"
	"time"
)

const (
	// Default threshold is 120% of cluster average
	defaultThreshold float64 = 1.2
)

// NoDelay is simply the zero value for time and meant to be a more meaningful
// value for CanClaim methods to return instead of initializing a new empty
// time struct.
var NoDelay = time.Time{}

// BalancerContext is a limited interface exposed to Balancers from the
// Consumer for access to limited Consumer state.
type BalancerContext interface {
	// Tasks returns a sorted list of task IDs run by this Consumer. The Consumer
	// stops task manipulations during claiming and balancing, so the list will
	// be accurate unless a task naturally completes.
	Tasks() []Task
}

// Balancer is the core task balancing interface. Without a master Metafora
// clusters are cooperatively balanced -- meaning each node needs to know how
// to balance itself.
type Balancer interface {
	// Init is called once and only once before any other Balancer methods are
	// called. The context argument is meant to expose functionality that might
	// be useful for CanClaim and Balance implementations.
	Init(BalancerContext)

	// CanClaim should return true if the consumer should accept a task.
	//
	// When denying a claim by returning false, CanClaim should return the time
	// at which to reconsider the task for claiming.
	CanClaim(taskID string) (ignoreUntil time.Time, claim bool)

	// Balance should return the list of Task IDs that should be released. The
	// criteria used to determine which tasks should be released is left up to
	// the implementation.
	Balance() (release []string)
}

// DumbBalancer is the simplest possible balancer implementation which simply
// accepts all tasks. Since it has no state a single global instance exists.
var DumbBalancer = dumbBalancer{}

type dumbBalancer struct{}

// Init does nothing.
func (dumbBalancer) Init(BalancerContext) {}

// CanClaim always returns true.
func (dumbBalancer) CanClaim(string) (time.Time, bool) { return NoDelay, true }

// Balance never returns any tasks to balance.
func (dumbBalancer) Balance() []string { return nil }

// Provides information about the cluster to be used by FairBalancer
type ClusterState interface {
	// Provide the current number of jobs
	NodeTaskCount() (map[string]int, error)
}

// NewDefaultFairBalancer creates a new FairBalancer but requires a
// ClusterState implementation to gain more information about the cluster than
// BalancerContext provides.
func NewDefaultFairBalancer(nodeid string, cs ClusterState) Balancer {
	return NewDefaultFairBalancerWithThreshold(nodeid, cs, defaultThreshold)
}

// NewDefaultFairBalancerWithThreshold allows callers to override
// FairBalancer's default 120% task load release threshold.
func NewDefaultFairBalancerWithThreshold(nodeid string, cs ClusterState, threshold float64) Balancer {
	return &FairBalancer{
		nodeid:           nodeid,
		clusterstate:     cs,
		releaseThreshold: threshold,
	}
}

// An implementation of Balancer which attempts to randomly release tasks in
// the case when the count of those currently running on this node is greater
// than some percentage of the cluster average (default 120%).
//
// This balancer will claim all tasks which were not released on the last call
// to Balance.
type FairBalancer struct {
	nodeid string

	bc           BalancerContext
	clusterstate ClusterState

	releaseThreshold float64
	delay            time.Time
}

func (e *FairBalancer) Init(s BalancerContext) {
	e.bc = s
}

// CanClaim rejects tasks if the last balance released tasks. Otherwise all
// tasks are accepted.
func (e *FairBalancer) CanClaim(taskid string) (time.Time, bool) {
	if e.delay.After(time.Now()) {
		// Return delay set by Balance()
		return e.delay, false
	}
	return NoDelay, true
}

// Balance releases tasks if this node has 120% more tasks than the average
// node in the cluster.
func (e *FairBalancer) Balance() []string {
	nodetasks := e.bc.Tasks()

	// Reset delay
	e.delay = time.Time{}

	// If local tasks <= 1 this node should never rebalance
	if len(nodetasks) < 2 {
		return nil
	}

	current, err := e.clusterstate.NodeTaskCount()
	if err != nil {
		Warnf("Error retrieving cluster state: %v", err)
		return nil
	}

	shouldrelease := current[e.nodeid] - e.desiredCount(current)
	if shouldrelease < 1 {
		return nil
	}

	releasetasks := make([]string, 0, shouldrelease)
	releaseset := make(map[string]struct{}, shouldrelease)

	random := rand.New(rand.NewSource(time.Now().UnixNano()))
	for len(releasetasks) < shouldrelease {
		tid := nodetasks[random.Intn(len(nodetasks))].ID()
		if _, ok := releaseset[tid]; !ok {
			releasetasks = append(releasetasks, tid)
			releaseset[tid] = struct{}{}
		}
	}

	e.delay = time.Now().Add(time.Duration(len(releasetasks)) * time.Second)
	return releasetasks
}

// Retrieve the desired maximum count, based on current cluster state
func (e *FairBalancer) desiredCount(current map[string]int) int {
	total := 0
	for _, c := range current {
		total += c
	}

	avg := 0
	if len(current) > 0 {
		avg = total / len(current)
	}

	return int(math.Ceil(float64(avg) * e.releaseThreshold))
}
<|endoftext|>


<commit_before>package monitor

import (
	"flag"
	"fmt"
	"sync"

	"github.com/hashicorp/consul/api"
	"github.com/hashicorp/consul/command/flags"
	"github.com/mitchellh/cli"
)

// cmd is a Command implementation that queries a running
// Consul agent what members are part of the cluster currently.
type cmd struct {
	UI    cli.Ui
	help  string
	flags *flag.FlagSet
	http  *flags.HTTPFlags

	shutdownCh <-chan struct{}

	lock     sync.Mutex
	quitting bool

	// flags
	logLevel string
	logJSON  bool
}

func New(ui cli.Ui, shutdownCh <-chan struct{}) *cmd {
	c := &cmd{UI: ui, shutdownCh: shutdownCh}
	c.init()
	return c
}

func (c *cmd) init() {
	c.flags = flag.NewFlagSet("", flag.ContinueOnError)
	c.flags.StringVar(&c.logLevel, "log-level", "INFO",
		"Log level of the agent.")
	c.flags.BoolVar(&c.logJSON, "log-json", false,
		"Output logs in JSON format.")

	c.http = &flags.HTTPFlags{}
	flags.Merge(c.flags, c.http.ClientFlags())
	c.help = flags.Usage(help, c.flags)
}

func (c *cmd) Run(args []string) int {
	var logCh chan string
	var err error
	var client *api.Client

	if err = c.flags.Parse(args); err != nil {
		return 1
	}

	client, err = c.http.APIClient()
	if err != nil {
		c.UI.Error(fmt.Sprintf("Error connecting to Consul agent: %s", err))
		return 1
	}

	eventDoneCh := make(chan struct{})
	if c.logJSON {
		logCh, err = client.Agent().MonitorJSON(c.logLevel, eventDoneCh, nil)
	}
	logCh, err = client.Agent().Monitor(c.logLevel, eventDoneCh, nil)
	if err != nil {
		c.UI.Error(fmt.Sprintf("Error starting monitor: %s", err))
		return 1
	}

	go func() {
		defer close(eventDoneCh)
	OUTER:
		for {
			select {
			case log := <-logCh:
				if log == "" {
					break OUTER
				}
				c.UI.Info(log)
			}
		}

		c.lock.Lock()
		defer c.lock.Unlock()
		if !c.quitting {
			c.UI.Info("")
			c.UI.Output("Remote side ended the monitor! This usually means that the\n" +
				"remote side has exited or crashed.")
		}
	}()

	select {
	case <-eventDoneCh:
		return 1
	case <-c.shutdownCh:
		c.lock.Lock()
		c.quitting = true
		c.lock.Unlock()
	}

	return 0
}

func (c *cmd) Synopsis() string {
	return synopsis
}

func (c *cmd) Help() string {
	return c.help
}

const synopsis = "Stream logs from a Consul agent"
const help = `
Usage: consul monitor [options]

  Shows recent log messages of a Consul agent, and attaches to the agent,
  outputting log messages as they occur in real time. The monitor lets you
  listen for log levels that may be filtered out of the Consul agent. For
  example your agent may only be logging at INFO level, but with the monitor
  you can see the DEBUG level logs.
`
<commit_msg>monitor: fix dropped error (#7206)<commit_after>package monitor

import (
	"flag"
	"fmt"
	"sync"

	"github.com/hashicorp/consul/api"
	"github.com/hashicorp/consul/command/flags"
	"github.com/mitchellh/cli"
)

// cmd is a Command implementation that queries a running
// Consul agent what members are part of the cluster currently.
type cmd struct {
	UI    cli.Ui
	help  string
	flags *flag.FlagSet
	http  *flags.HTTPFlags

	shutdownCh <-chan struct{}

	lock     sync.Mutex
	quitting bool

	// flags
	logLevel string
	logJSON  bool
}

func New(ui cli.Ui, shutdownCh <-chan struct{}) *cmd {
	c := &cmd{UI: ui, shutdownCh: shutdownCh}
	c.init()
	return c
}

func (c *cmd) init() {
	c.flags = flag.NewFlagSet("", flag.ContinueOnError)
	c.flags.StringVar(&c.logLevel, "log-level", "INFO",
		"Log level of the agent.")
	c.flags.BoolVar(&c.logJSON, "log-json", false,
		"Output logs in JSON format.")

	c.http = &flags.HTTPFlags{}
	flags.Merge(c.flags, c.http.ClientFlags())
	c.help = flags.Usage(help, c.flags)
}

func (c *cmd) Run(args []string) int {
	var logCh chan string
	var err error
	var client *api.Client

	if err = c.flags.Parse(args); err != nil {
		return 1
	}

	client, err = c.http.APIClient()
	if err != nil {
		c.UI.Error(fmt.Sprintf("Error connecting to Consul agent: %s", err))
		return 1
	}

	eventDoneCh := make(chan struct{})
	if c.logJSON {
		logCh, err = client.Agent().MonitorJSON(c.logLevel, eventDoneCh, nil)
		if err != nil {
			c.UI.Error(fmt.Sprintf("Error starting JSON monitor: %s", err))
			return 1
		}
	}
	logCh, err = client.Agent().Monitor(c.logLevel, eventDoneCh, nil)
	if err != nil {
		c.UI.Error(fmt.Sprintf("Error starting monitor: %s", err))
		return 1
	}

	go func() {
		defer close(eventDoneCh)
	OUTER:
		for {
			select {
			case log := <-logCh:
				if log == "" {
					break OUTER
				}
				c.UI.Info(log)
			}
		}

		c.lock.Lock()
		defer c.lock.Unlock()
		if !c.quitting {
			c.UI.Info("")
			c.UI.Output("Remote side ended the monitor! This usually means that the\n" +
				"remote side has exited or crashed.")
		}
	}()

	select {
	case <-eventDoneCh:
		return 1
	case <-c.shutdownCh:
		c.lock.Lock()
		c.quitting = true
		c.lock.Unlock()
	}

	return 0
}

func (c *cmd) Synopsis() string {
	return synopsis
}

func (c *cmd) Help() string {
	return c.help
}

const synopsis = "Stream logs from a Consul agent"
const help = `
Usage: consul monitor [options]

  Shows recent log messages of a Consul agent, and attaches to the agent,
  outputting log messages as they occur in real time. The monitor lets you
  listen for log levels that may be filtered out of the Consul agent. For
  example your agent may only be logging at INFO level, but with the monitor
  you can see the DEBUG level logs.
`
<|endoftext|>