<commit_before>// +build linux

/*
Copyright 2015 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 e2enode

import (
	"fmt"
	"strings"
	"time"

	clientset "k8s.io/client-go/kubernetes"
	kubeletstatsv1alpha1 "k8s.io/kubelet/pkg/apis/stats/v1alpha1"
	"k8s.io/kubernetes/test/e2e/framework"
	e2ekubelet "k8s.io/kubernetes/test/e2e/framework/kubelet"
	e2eperf "k8s.io/kubernetes/test/e2e/framework/perf"
	imageutils "k8s.io/kubernetes/test/utils/image"

	"github.com/onsi/ginkgo"
)

var _ = SIGDescribe("Resource-usage [Serial] [Slow]", func() {
	const (
		// Interval to poll /stats/container on a node
		containerStatsPollingPeriod = 10 * time.Second
	)

	var (
		rc *ResourceCollector
		om *e2ekubelet.RuntimeOperationMonitor
	)

	f := framework.NewDefaultFramework("resource-usage")

	ginkgo.BeforeEach(func() {
		om = e2ekubelet.NewRuntimeOperationMonitor(f.ClientSet)
		// The test collects resource usage from a standalone Cadvisor pod.
		// The Cadvsior of Kubelet has a housekeeping interval of 10s, which is too long to
		// show the resource usage spikes. But changing its interval increases the overhead
		// of kubelet. Hence we use a Cadvisor pod.
		f.PodClient().CreateSync(getCadvisorPod())
		rc = NewResourceCollector(containerStatsPollingPeriod)
	})

	ginkgo.AfterEach(func() {
		result := om.GetLatestRuntimeOperationErrorRate()
		framework.Logf("runtime operation error metrics:\n%s", e2ekubelet.FormatRuntimeOperationErrorRate(result))
	})

	// This test measures and verifies the steady resource usage of node is within limit
	// It collects data from a standalone Cadvisor with housekeeping interval 1s.
	// It verifies CPU percentiles and the lastest memory usage.
	ginkgo.Context("regular resource usage tracking", func() {
		rTests := []resourceTest{
			{
				podsNr: 10,
				cpuLimits: e2ekubelet.ContainersCPUSummary{
					kubeletstatsv1alpha1.SystemContainerKubelet: {0.50: 0.30, 0.95: 0.35},
					kubeletstatsv1alpha1.SystemContainerRuntime: {0.50: 0.30, 0.95: 0.40},
				},
				memLimits: e2ekubelet.ResourceUsagePerContainer{
					kubeletstatsv1alpha1.SystemContainerKubelet: &e2ekubelet.ContainerResourceUsage{MemoryRSSInBytes: 200 * 1024 * 1024},
					kubeletstatsv1alpha1.SystemContainerRuntime: &e2ekubelet.ContainerResourceUsage{MemoryRSSInBytes: 400 * 1024 * 1024},
				},
			},
		}

		for _, testArg := range rTests {
			itArg := testArg
			desc := fmt.Sprintf("resource tracking for %d pods per node", itArg.podsNr)
			ginkgo.It(desc, func() {
				testInfo := getTestNodeInfo(f, itArg.getTestName(), desc)

				runResourceUsageTest(f, rc, itArg)

				// Log and verify resource usage
				logAndVerifyResource(f, rc, itArg.cpuLimits, itArg.memLimits, testInfo, true)
			})
		}
	})

	ginkgo.Context("regular resource usage tracking", func() {
		rTests := []resourceTest{
			{
				podsNr: 0,
			},
			{
				podsNr: 10,
			},
			{
				podsNr: 35,
			},
			{
				podsNr: 105,
			},
		}

		for _, testArg := range rTests {
			itArg := testArg
			desc := fmt.Sprintf("resource tracking for %d pods per node [Benchmark]", itArg.podsNr)
			ginkgo.It(desc, func() {
				testInfo := getTestNodeInfo(f, itArg.getTestName(), desc)

				runResourceUsageTest(f, rc, itArg)

				// Log and verify resource usage
				logAndVerifyResource(f, rc, itArg.cpuLimits, itArg.memLimits, testInfo, false)
			})
		}
	})
})

type resourceTest struct {
	podsNr    int
	cpuLimits e2ekubelet.ContainersCPUSummary
	memLimits e2ekubelet.ResourceUsagePerContainer
}

func (rt *resourceTest) getTestName() string {
	return fmt.Sprintf("resource_%d", rt.podsNr)
}

// runResourceUsageTest runs the resource usage test
func runResourceUsageTest(f *framework.Framework, rc *ResourceCollector, testArg resourceTest) {
	const (
		// The monitoring time for one test
		monitoringTime = 10 * time.Minute
		// The periodic reporting period
		reportingPeriod = 5 * time.Minute
		// sleep for an interval here to measure steady data
		sleepAfterCreatePods = 10 * time.Second
	)
	pods := newTestPods(testArg.podsNr, true, imageutils.GetPauseImageName(), "test_pod")

	rc.Start()
	// Explicitly delete pods to prevent namespace controller cleanning up timeout
	defer deletePodsSync(f, append(pods, getCadvisorPod()))
	defer rc.Stop()

	ginkgo.By("Creating a batch of Pods")
	f.PodClient().CreateBatch(pods)

	// wait for a while to let the node be steady
	time.Sleep(sleepAfterCreatePods)

	// Log once and flush the stats.
	rc.LogLatest()
	rc.Reset()

	ginkgo.By("Start monitoring resource usage")
	// Periodically dump the cpu summary until the deadline is met.
	// Note that without calling e2ekubelet.ResourceMonitor.Reset(), the stats
	// would occupy increasingly more memory. This should be fine
	// for the current test duration, but we should reclaim the
	// entries if we plan to monitor longer (e.g., 8 hours).
	deadline := time.Now().Add(monitoringTime)
	for time.Now().Before(deadline) {
		timeLeft := deadline.Sub(time.Now())
		framework.Logf("Still running...%v left", timeLeft)
		if timeLeft < reportingPeriod {
			time.Sleep(timeLeft)
		} else {
			time.Sleep(reportingPeriod)
		}
		logPods(f.ClientSet)
	}

	ginkgo.By("Reporting overall resource usage")
	logPods(f.ClientSet)
}

// logAndVerifyResource prints the resource usage as perf data and verifies whether resource usage satisfies the limit.
func logAndVerifyResource(f *framework.Framework, rc *ResourceCollector, cpuLimits e2ekubelet.ContainersCPUSummary,
	memLimits e2ekubelet.ResourceUsagePerContainer, testInfo map[string]string, isVerify bool) {
	nodeName := framework.TestContext.NodeName

	// Obtain memory PerfData
	usagePerContainer, err := rc.GetLatest()
	framework.ExpectNoError(err)
	framework.Logf("%s", formatResourceUsageStats(usagePerContainer))

	usagePerNode := make(e2ekubelet.ResourceUsagePerNode)
	usagePerNode[nodeName] = usagePerContainer

	// Obtain CPU PerfData
	cpuSummary := rc.GetCPUSummary()
	framework.Logf("%s", formatCPUSummary(cpuSummary))

	cpuSummaryPerNode := make(e2ekubelet.NodesCPUSummary)
	cpuSummaryPerNode[nodeName] = cpuSummary

	// Print resource usage
	logPerfData(e2eperf.ResourceUsageToPerfDataWithLabels(usagePerNode, testInfo), "memory")
	logPerfData(e2eperf.CPUUsageToPerfDataWithLabels(cpuSummaryPerNode, testInfo), "cpu")

	// Verify resource usage
	if isVerify {
		verifyMemoryLimits(f.ClientSet, memLimits, usagePerNode)
		verifyCPULimits(cpuLimits, cpuSummaryPerNode)
	}
}

func verifyMemoryLimits(c clientset.Interface, expected e2ekubelet.ResourceUsagePerContainer, actual e2ekubelet.ResourceUsagePerNode) {
	if expected == nil {
		return
	}
	var errList []string
	for nodeName, nodeSummary := range actual {
		var nodeErrs []string
		for cName, expectedResult := range expected {
			container, ok := nodeSummary[cName]
			if !ok {
				nodeErrs = append(nodeErrs, fmt.Sprintf("container %q: missing", cName))
				continue
			}

			expectedValue := expectedResult.MemoryRSSInBytes
			actualValue := container.MemoryRSSInBytes
			if expectedValue != 0 && actualValue > expectedValue {
				nodeErrs = append(nodeErrs, fmt.Sprintf("container %q: expected RSS memory (MB) < %d; got %d",
					cName, expectedValue, actualValue))
			}
		}
		if len(nodeErrs) > 0 {
			errList = append(errList, fmt.Sprintf("node %v:\n %s", nodeName, strings.Join(nodeErrs, ", ")))
			heapStats, err := e2ekubelet.GetKubeletHeapStats(c, nodeName)
			if err != nil {
				framework.Logf("Unable to get heap stats from %q", nodeName)
			} else {
				framework.Logf("Heap stats on %q\n:%v", nodeName, heapStats)
			}
		}
	}
	if len(errList) > 0 {
		framework.Failf("Memory usage exceeding limits:\n %s", strings.Join(errList, "\n"))
	}
}

func verifyCPULimits(expected e2ekubelet.ContainersCPUSummary, actual e2ekubelet.NodesCPUSummary) {
	if expected == nil {
		return
	}
	var errList []string
	for nodeName, perNodeSummary := range actual {
		var nodeErrs []string
		for cName, expectedResult := range expected {
			perContainerSummary, ok := perNodeSummary[cName]
			if !ok {
				nodeErrs = append(nodeErrs, fmt.Sprintf("container %q: missing", cName))
				continue
			}
			for p, expectedValue := range expectedResult {
				actualValue, ok := perContainerSummary[p]
				if !ok {
					nodeErrs = append(nodeErrs, fmt.Sprintf("container %q: missing percentile %v", cName, p))
					continue
				}
				if actualValue > expectedValue {
					nodeErrs = append(nodeErrs, fmt.Sprintf("container %q: expected %.0fth%% usage < %.3f; got %.3f",
						cName, p*100, expectedValue, actualValue))
				}
			}
		}
		if len(nodeErrs) > 0 {
			errList = append(errList, fmt.Sprintf("node %v:\n %s", nodeName, strings.Join(nodeErrs, ", ")))
		}
	}
	if len(errList) > 0 {
		framework.Failf("CPU usage exceeding limits:\n %s", strings.Join(errList, "\n"))
	}
}

func logPods(c clientset.Interface) {
	nodeName := framework.TestContext.NodeName
	podList, err := e2ekubelet.GetKubeletRunningPods(c, nodeName)
	if err != nil {
		framework.Logf("Unable to retrieve kubelet pods for node %v", nodeName)
	}
	framework.Logf("%d pods are running on node %v", len(podList.Items), nodeName)
}
<commit_msg>enable benchmark by matching test config<commit_after>// +build linux

/*
Copyright 2015 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 e2enode

import (
	"fmt"
	"strings"
	"time"

	clientset "k8s.io/client-go/kubernetes"
	kubeletstatsv1alpha1 "k8s.io/kubelet/pkg/apis/stats/v1alpha1"
	"k8s.io/kubernetes/test/e2e/framework"
	e2ekubelet "k8s.io/kubernetes/test/e2e/framework/kubelet"
	e2eperf "k8s.io/kubernetes/test/e2e/framework/perf"
	imageutils "k8s.io/kubernetes/test/utils/image"

	"github.com/onsi/ginkgo"
)

var _ = SIGDescribe("Resource-usage [Serial] [Slow]", func() {
	const (
		// Interval to poll /stats/container on a node
		containerStatsPollingPeriod = 10 * time.Second
	)

	var (
		rc *ResourceCollector
		om *e2ekubelet.RuntimeOperationMonitor
	)

	f := framework.NewDefaultFramework("resource-usage")

	ginkgo.BeforeEach(func() {
		om = e2ekubelet.NewRuntimeOperationMonitor(f.ClientSet)
		// The test collects resource usage from a standalone Cadvisor pod.
		// The Cadvsior of Kubelet has a housekeeping interval of 10s, which is too long to
		// show the resource usage spikes. But changing its interval increases the overhead
		// of kubelet. Hence we use a Cadvisor pod.
		f.PodClient().CreateSync(getCadvisorPod())
		rc = NewResourceCollector(containerStatsPollingPeriod)
	})

	ginkgo.AfterEach(func() {
		result := om.GetLatestRuntimeOperationErrorRate()
		framework.Logf("runtime operation error metrics:\n%s", e2ekubelet.FormatRuntimeOperationErrorRate(result))
	})

	// This test measures and verifies the steady resource usage of node is within limit
	// It collects data from a standalone Cadvisor with housekeeping interval 1s.
	// It verifies CPU percentiles and the lastest memory usage.
	ginkgo.Context("regular resource usage tracking", func() {
		rTests := []resourceTest{
			{
				podsNr: 10,
				cpuLimits: e2ekubelet.ContainersCPUSummary{
					kubeletstatsv1alpha1.SystemContainerKubelet: {0.50: 0.30, 0.95: 0.35},
					kubeletstatsv1alpha1.SystemContainerRuntime: {0.50: 0.30, 0.95: 0.40},
				},
				memLimits: e2ekubelet.ResourceUsagePerContainer{
					kubeletstatsv1alpha1.SystemContainerKubelet: &e2ekubelet.ContainerResourceUsage{MemoryRSSInBytes: 200 * 1024 * 1024},
					kubeletstatsv1alpha1.SystemContainerRuntime: &e2ekubelet.ContainerResourceUsage{MemoryRSSInBytes: 400 * 1024 * 1024},
				},
			},
		}

		for _, testArg := range rTests {
			itArg := testArg
			desc := fmt.Sprintf("resource tracking for %d pods per node", itArg.podsNr)
			ginkgo.It(desc, func() {
				testInfo := getTestNodeInfo(f, itArg.getTestName(), desc)

				runResourceUsageTest(f, rc, itArg)

				// Log and verify resource usage
				logAndVerifyResource(f, rc, itArg.cpuLimits, itArg.memLimits, testInfo, true)
			})
		}
	})

	ginkgo.Context("regular resource usage tracking", func() {
		rTests := []resourceTest{
			{
				podsNr: 0,
			},
			{
				podsNr: 10,
			},
			{
				podsNr: 35,
			},
			{
				podsNr: 90,
			},
		}

		for _, testArg := range rTests {
			itArg := testArg
			desc := fmt.Sprintf("resource tracking for %d pods per node [Benchmark]", itArg.podsNr)
			ginkgo.It(desc, func() {
				testInfo := getTestNodeInfo(f, itArg.getTestName(), desc)

				runResourceUsageTest(f, rc, itArg)

				// Log and verify resource usage
				logAndVerifyResource(f, rc, itArg.cpuLimits, itArg.memLimits, testInfo, false)
			})
		}
	})
})

type resourceTest struct {
	podsNr    int
	cpuLimits e2ekubelet.ContainersCPUSummary
	memLimits e2ekubelet.ResourceUsagePerContainer
}

func (rt *resourceTest) getTestName() string {
	return fmt.Sprintf("resource_%d", rt.podsNr)
}

// runResourceUsageTest runs the resource usage test
func runResourceUsageTest(f *framework.Framework, rc *ResourceCollector, testArg resourceTest) {
	const (
		// The monitoring time for one test
		monitoringTime = 10 * time.Minute
		// The periodic reporting period
		reportingPeriod = 5 * time.Minute
		// sleep for an interval here to measure steady data
		sleepAfterCreatePods = 10 * time.Second
	)
	pods := newTestPods(testArg.podsNr, true, imageutils.GetPauseImageName(), "test_pod")

	rc.Start()
	// Explicitly delete pods to prevent namespace controller cleanning up timeout
	defer deletePodsSync(f, append(pods, getCadvisorPod()))
	defer rc.Stop()

	ginkgo.By("Creating a batch of Pods")
	f.PodClient().CreateBatch(pods)

	// wait for a while to let the node be steady
	time.Sleep(sleepAfterCreatePods)

	// Log once and flush the stats.
	rc.LogLatest()
	rc.Reset()

	ginkgo.By("Start monitoring resource usage")
	// Periodically dump the cpu summary until the deadline is met.
	// Note that without calling e2ekubelet.ResourceMonitor.Reset(), the stats
	// would occupy increasingly more memory. This should be fine
	// for the current test duration, but we should reclaim the
	// entries if we plan to monitor longer (e.g., 8 hours).
	deadline := time.Now().Add(monitoringTime)
	for time.Now().Before(deadline) {
		timeLeft := deadline.Sub(time.Now())
		framework.Logf("Still running...%v left", timeLeft)
		if timeLeft < reportingPeriod {
			time.Sleep(timeLeft)
		} else {
			time.Sleep(reportingPeriod)
		}
		logPods(f.ClientSet)
	}

	ginkgo.By("Reporting overall resource usage")
	logPods(f.ClientSet)
}

// logAndVerifyResource prints the resource usage as perf data and verifies whether resource usage satisfies the limit.
func logAndVerifyResource(f *framework.Framework, rc *ResourceCollector, cpuLimits e2ekubelet.ContainersCPUSummary,
	memLimits e2ekubelet.ResourceUsagePerContainer, testInfo map[string]string, isVerify bool) {
	nodeName := framework.TestContext.NodeName

	// Obtain memory PerfData
	usagePerContainer, err := rc.GetLatest()
	framework.ExpectNoError(err)
	framework.Logf("%s", formatResourceUsageStats(usagePerContainer))

	usagePerNode := make(e2ekubelet.ResourceUsagePerNode)
	usagePerNode[nodeName] = usagePerContainer

	// Obtain CPU PerfData
	cpuSummary := rc.GetCPUSummary()
	framework.Logf("%s", formatCPUSummary(cpuSummary))

	cpuSummaryPerNode := make(e2ekubelet.NodesCPUSummary)
	cpuSummaryPerNode[nodeName] = cpuSummary

	// Print resource usage
	logPerfData(e2eperf.ResourceUsageToPerfDataWithLabels(usagePerNode, testInfo), "memory")
	logPerfData(e2eperf.CPUUsageToPerfDataWithLabels(cpuSummaryPerNode, testInfo), "cpu")

	// Verify resource usage
	if isVerify {
		verifyMemoryLimits(f.ClientSet, memLimits, usagePerNode)
		verifyCPULimits(cpuLimits, cpuSummaryPerNode)
	}
}

func verifyMemoryLimits(c clientset.Interface, expected e2ekubelet.ResourceUsagePerContainer, actual e2ekubelet.ResourceUsagePerNode) {
	if expected == nil {
		return
	}
	var errList []string
	for nodeName, nodeSummary := range actual {
		var nodeErrs []string
		for cName, expectedResult := range expected {
			container, ok := nodeSummary[cName]
			if !ok {
				nodeErrs = append(nodeErrs, fmt.Sprintf("container %q: missing", cName))
				continue
			}

			expectedValue := expectedResult.MemoryRSSInBytes
			actualValue := container.MemoryRSSInBytes
			if expectedValue != 0 && actualValue > expectedValue {
				nodeErrs = append(nodeErrs, fmt.Sprintf("container %q: expected RSS memory (MB) < %d; got %d",
					cName, expectedValue, actualValue))
			}
		}
		if len(nodeErrs) > 0 {
			errList = append(errList, fmt.Sprintf("node %v:\n %s", nodeName, strings.Join(nodeErrs, ", ")))
			heapStats, err := e2ekubelet.GetKubeletHeapStats(c, nodeName)
			if err != nil {
				framework.Logf("Unable to get heap stats from %q", nodeName)
			} else {
				framework.Logf("Heap stats on %q\n:%v", nodeName, heapStats)
			}
		}
	}
	if len(errList) > 0 {
		framework.Failf("Memory usage exceeding limits:\n %s", strings.Join(errList, "\n"))
	}
}

func verifyCPULimits(expected e2ekubelet.ContainersCPUSummary, actual e2ekubelet.NodesCPUSummary) {
	if expected == nil {
		return
	}
	var errList []string
	for nodeName, perNodeSummary := range actual {
		var nodeErrs []string
		for cName, expectedResult := range expected {
			perContainerSummary, ok := perNodeSummary[cName]
			if !ok {
				nodeErrs = append(nodeErrs, fmt.Sprintf("container %q: missing", cName))
				continue
			}
			for p, expectedValue := range expectedResult {
				actualValue, ok := perContainerSummary[p]
				if !ok {
					nodeErrs = append(nodeErrs, fmt.Sprintf("container %q: missing percentile %v", cName, p))
					continue
				}
				if actualValue > expectedValue {
					nodeErrs = append(nodeErrs, fmt.Sprintf("container %q: expected %.0fth%% usage < %.3f; got %.3f",
						cName, p*100, expectedValue, actualValue))
				}
			}
		}
		if len(nodeErrs) > 0 {
			errList = append(errList, fmt.Sprintf("node %v:\n %s", nodeName, strings.Join(nodeErrs, ", ")))
		}
	}
	if len(errList) > 0 {
		framework.Failf("CPU usage exceeding limits:\n %s", strings.Join(errList, "\n"))
	}
}

func logPods(c clientset.Interface) {
	nodeName := framework.TestContext.NodeName
	podList, err := e2ekubelet.GetKubeletRunningPods(c, nodeName)
	if err != nil {
		framework.Logf("Unable to retrieve kubelet pods for node %v", nodeName)
	}
	framework.Logf("%d pods are running on node %v", len(podList.Items), nodeName)
}
<|endoftext|>


<commit_before>/*
Copyright 2014 The Kubernetes Authors All rights reserved.

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

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

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

package e2e

import (
	"fmt"
	"net/http"
	"strings"
	"time"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/util/intstr"
	"k8s.io/kubernetes/test/e2e/framework"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = framework.KubeDescribe("Networking", func() {
	f := framework.NewDefaultFramework("nettest")

	var svcname = "nettest"

	BeforeEach(func() {
		//Assert basic external connectivity.
		//Since this is not really a test of kubernetes in any way, we
		//leave it as a pre-test assertion, rather than a Ginko test.
		By("Executing a successful http request from the external internet")
		resp, err := http.Get("http://google.com")
		if err != nil {
			framework.Failf("Unable to connect/talk to the internet: %v", err)
		}
		if resp.StatusCode != http.StatusOK {
			framework.Failf("Unexpected error code, expected 200, got, %v (%v)", resp.StatusCode, resp)
		}
	})

	It("should provide Internet connection for containers [Conformance]", func() {
		By("Running container which tries to wget google.com")
		framework.ExpectNoError(framework.CheckConnectivityToHost(f, "", "wget-test", "google.com"))
	})

	// First test because it has no dependencies on variables created later on.
	It("should provide unchanging, static URL paths for kubernetes api services [Conformance]", func() {
		tests := []struct {
			path string
		}{
			{path: "/validate"},
			{path: "/healthz"},
			// TODO: test proxy links here
		}
		for _, test := range tests {
			By(fmt.Sprintf("testing: %s", test.path))
			data, err := f.Client.RESTClient.Get().
				Namespace(f.Namespace.Name).
				AbsPath(test.path).
				DoRaw()
			if err != nil {
				framework.Failf("Failed: %v\nBody: %s", err, string(data))
			}
		}
	})

	//Now we can proceed with the test.
	It("should function for intra-pod communication [Conformance]", func() {

		By(fmt.Sprintf("Creating a service named %q in namespace %q", svcname, f.Namespace.Name))
		svc, err := f.Client.Services(f.Namespace.Name).Create(&api.Service{
			ObjectMeta: api.ObjectMeta{
				Name: svcname,
				Labels: map[string]string{
					"name": svcname,
				},
			},
			Spec: api.ServiceSpec{
				Ports: []api.ServicePort{{
					Protocol:   "TCP",
					Port:       8080,
					TargetPort: intstr.FromInt(8080),
				}},
				Selector: map[string]string{
					"name": svcname,
				},
			},
		})
		if err != nil {
			framework.Failf("unable to create test service named [%s] %v", svc.Name, err)
		}

		// Clean up service
		defer func() {
			By("Cleaning up the service")
			if err = f.Client.Services(f.Namespace.Name).Delete(svc.Name); err != nil {
				framework.Failf("unable to delete svc %v: %v", svc.Name, err)
			}
		}()

		By("Creating a webserver (pending) pod on each node")

		nodes, err := framework.GetReadyNodes(f)
		framework.ExpectNoError(err)

		if len(nodes.Items) == 1 {
			// in general, the test requires two nodes. But for local development, often a one node cluster
			// is created, for simplicity and speed. (see issue #10012). We permit one-node test
			// only in some cases
			if !framework.ProviderIs("local") {
				framework.Failf(fmt.Sprintf("The test requires two Ready nodes on %s, but found just one.", framework.TestContext.Provider))
			}
			framework.Logf("Only one ready node is detected. The test has limited scope in such setting. " +
				"Rerun it with at least two nodes to get complete coverage.")
		}

		podNames := LaunchNetTestPodPerNode(f, nodes, svcname, "1.8")

		// Clean up the pods
		defer func() {
			By("Cleaning up the webserver pods")
			for _, podName := range podNames {
				if err = f.Client.Pods(f.Namespace.Name).Delete(podName, nil); err != nil {
					framework.Logf("Failed to delete pod %s: %v", podName, err)
				}
			}
		}()

		By("Waiting for the webserver pods to transition to Running state")
		for _, podName := range podNames {
			err = f.WaitForPodRunning(podName)
			Expect(err).NotTo(HaveOccurred())
		}

		By("Waiting for connectivity to be verified")
		passed := false

		//once response OK, evaluate response body for pass/fail.
		var body []byte
		getDetails := func() ([]byte, error) {
			proxyRequest, errProxy := framework.GetServicesProxyRequest(f.Client, f.Client.Get())
			if errProxy != nil {
				return nil, errProxy
			}
			return proxyRequest.Namespace(f.Namespace.Name).
				Name(svc.Name).
				Suffix("read").
				DoRaw()
		}

		getStatus := func() ([]byte, error) {
			proxyRequest, errProxy := framework.GetServicesProxyRequest(f.Client, f.Client.Get())
			if errProxy != nil {
				return nil, errProxy
			}
			return proxyRequest.Namespace(f.Namespace.Name).
				Name(svc.Name).
				Suffix("status").
				DoRaw()
		}

		// nettest containers will wait for all service endpoints to come up for 2 minutes
		// apply a 3 minutes observation period here to avoid this test to time out before the nettest starts to contact peers
		timeout := time.Now().Add(3 * time.Minute)
		for i := 0; !passed && timeout.After(time.Now()); i++ {
			time.Sleep(2 * time.Second)
			framework.Logf("About to make a proxy status call")
			start := time.Now()
			body, err = getStatus()
			framework.Logf("Proxy status call returned in %v", time.Since(start))
			if err != nil {
				framework.Logf("Attempt %v: service/pod still starting. (error: '%v')", i, err)
				continue
			}
			// Finally, we pass/fail the test based on if the container's response body, as to whether or not it was able to find peers.
			switch {
			case string(body) == "pass":
				framework.Logf("Passed on attempt %v. Cleaning up.", i)
				passed = true
			case string(body) == "running":
				framework.Logf("Attempt %v: test still running", i)
			case string(body) == "fail":
				if body, err = getDetails(); err != nil {
					framework.Failf("Failed on attempt %v. Cleaning up. Error reading details: %v", i, err)
				} else {
					framework.Failf("Failed on attempt %v. Cleaning up. Details:\n%s", i, string(body))
				}
			case strings.Contains(string(body), "no endpoints available"):
				framework.Logf("Attempt %v: waiting on service/endpoints", i)
			default:
				framework.Logf("Unexpected response:\n%s", body)
			}
		}

		if !passed {
			if body, err = getDetails(); err != nil {
				framework.Failf("Timed out. Cleaning up. Error reading details: %v", err)
			} else {
				framework.Failf("Timed out. Cleaning up. Details:\n%s", string(body))
			}
		}
		Expect(string(body)).To(Equal("pass"))
	})

	// Marked with [Flaky] until the tests prove themselves stable.
	framework.KubeDescribe("[Flaky] Granular Checks", func() {

		It("should function for pod communication on a single node", func() {

			By("Picking a node")
			nodes, err := framework.GetReadyNodes(f)
			framework.ExpectNoError(err)
			node := nodes.Items[0]

			By("Creating a webserver pod")
			podName := "same-node-webserver"
			defer f.Client.Pods(f.Namespace.Name).Delete(podName, nil)
			ip := framework.LaunchWebserverPod(f, podName, node.Name)

			By("Checking that the webserver is accessible from a pod on the same node")
			framework.ExpectNoError(framework.CheckConnectivityToHost(f, node.Name, "same-node-wget", ip))
		})

		It("should function for pod communication between nodes", func() {

			podClient := f.Client.Pods(f.Namespace.Name)

			By("Picking multiple nodes")
			nodes, err := framework.GetReadyNodes(f)
			framework.ExpectNoError(err)

			if len(nodes.Items) == 1 {
				framework.Skipf("The test requires two Ready nodes on %s, but found just one.", framework.TestContext.Provider)
			}

			node1 := nodes.Items[0]
			node2 := nodes.Items[1]

			By("Creating a webserver pod")
			podName := "different-node-webserver"
			defer podClient.Delete(podName, nil)
			ip := framework.LaunchWebserverPod(f, podName, node1.Name)

			By("Checking that the webserver is accessible from a pod on a different node")
			framework.ExpectNoError(framework.CheckConnectivityToHost(f, node2.Name, "different-node-wget", ip))
		})
	})
})

func LaunchNetTestPodPerNode(f *framework.Framework, nodes *api.NodeList, name, version string) []string {
	podNames := []string{}

	totalPods := len(nodes.Items)

	Expect(totalPods).NotTo(Equal(0))

	for _, node := range nodes.Items {
		pod, err := f.Client.Pods(f.Namespace.Name).Create(&api.Pod{
			ObjectMeta: api.ObjectMeta{
				GenerateName: name + "-",
				Labels: map[string]string{
					"name": name,
				},
			},
			Spec: api.PodSpec{
				Containers: []api.Container{
					{
						Name:  "webserver",
						Image: "gcr.io/google_containers/nettest:" + version,
						Args: []string{
							"-service=" + name,
							//peers >= totalPods should be asserted by the container.
							//the nettest container finds peers by looking up list of svc endpoints.
							fmt.Sprintf("-peers=%d", totalPods),
							"-namespace=" + f.Namespace.Name},
						Ports: []api.ContainerPort{{ContainerPort: 8080}},
					},
				},
				NodeName:      node.Name,
				RestartPolicy: api.RestartPolicyNever,
			},
		})
		Expect(err).NotTo(HaveOccurred())
		framework.Logf("Created pod %s on node %s", pod.ObjectMeta.Name, node.Name)
		podNames = append(podNames, pod.ObjectMeta.Name)
	}
	return podNames
}
<commit_msg>Remove flaky tag from e2e net granular<commit_after>/*
Copyright 2014 The Kubernetes Authors All rights reserved.

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

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

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

package e2e

import (
	"fmt"
	"net/http"
	"strings"
	"time"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/util/intstr"
	"k8s.io/kubernetes/test/e2e/framework"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = framework.KubeDescribe("Networking", func() {
	f := framework.NewDefaultFramework("nettest")

	var svcname = "nettest"

	BeforeEach(func() {
		//Assert basic external connectivity.
		//Since this is not really a test of kubernetes in any way, we
		//leave it as a pre-test assertion, rather than a Ginko test.
		By("Executing a successful http request from the external internet")
		resp, err := http.Get("http://google.com")
		if err != nil {
			framework.Failf("Unable to connect/talk to the internet: %v", err)
		}
		if resp.StatusCode != http.StatusOK {
			framework.Failf("Unexpected error code, expected 200, got, %v (%v)", resp.StatusCode, resp)
		}
	})

	It("should provide Internet connection for containers [Conformance]", func() {
		By("Running container which tries to wget google.com")
		framework.ExpectNoError(framework.CheckConnectivityToHost(f, "", "wget-test", "google.com"))
	})

	// First test because it has no dependencies on variables created later on.
	It("should provide unchanging, static URL paths for kubernetes api services [Conformance]", func() {
		tests := []struct {
			path string
		}{
			{path: "/validate"},
			{path: "/healthz"},
			// TODO: test proxy links here
		}
		for _, test := range tests {
			By(fmt.Sprintf("testing: %s", test.path))
			data, err := f.Client.RESTClient.Get().
				Namespace(f.Namespace.Name).
				AbsPath(test.path).
				DoRaw()
			if err != nil {
				framework.Failf("Failed: %v\nBody: %s", err, string(data))
			}
		}
	})

	//Now we can proceed with the test.
	It("should function for intra-pod communication [Conformance]", func() {

		By(fmt.Sprintf("Creating a service named %q in namespace %q", svcname, f.Namespace.Name))
		svc, err := f.Client.Services(f.Namespace.Name).Create(&api.Service{
			ObjectMeta: api.ObjectMeta{
				Name: svcname,
				Labels: map[string]string{
					"name": svcname,
				},
			},
			Spec: api.ServiceSpec{
				Ports: []api.ServicePort{{
					Protocol:   "TCP",
					Port:       8080,
					TargetPort: intstr.FromInt(8080),
				}},
				Selector: map[string]string{
					"name": svcname,
				},
			},
		})
		if err != nil {
			framework.Failf("unable to create test service named [%s] %v", svc.Name, err)
		}

		// Clean up service
		defer func() {
			By("Cleaning up the service")
			if err = f.Client.Services(f.Namespace.Name).Delete(svc.Name); err != nil {
				framework.Failf("unable to delete svc %v: %v", svc.Name, err)
			}
		}()

		By("Creating a webserver (pending) pod on each node")

		nodes, err := framework.GetReadyNodes(f)
		framework.ExpectNoError(err)

		if len(nodes.Items) == 1 {
			// in general, the test requires two nodes. But for local development, often a one node cluster
			// is created, for simplicity and speed. (see issue #10012). We permit one-node test
			// only in some cases
			if !framework.ProviderIs("local") {
				framework.Failf(fmt.Sprintf("The test requires two Ready nodes on %s, but found just one.", framework.TestContext.Provider))
			}
			framework.Logf("Only one ready node is detected. The test has limited scope in such setting. " +
				"Rerun it with at least two nodes to get complete coverage.")
		}

		podNames := LaunchNetTestPodPerNode(f, nodes, svcname, "1.8")

		// Clean up the pods
		defer func() {
			By("Cleaning up the webserver pods")
			for _, podName := range podNames {
				if err = f.Client.Pods(f.Namespace.Name).Delete(podName, nil); err != nil {
					framework.Logf("Failed to delete pod %s: %v", podName, err)
				}
			}
		}()

		By("Waiting for the webserver pods to transition to Running state")
		for _, podName := range podNames {
			err = f.WaitForPodRunning(podName)
			Expect(err).NotTo(HaveOccurred())
		}

		By("Waiting for connectivity to be verified")
		passed := false

		//once response OK, evaluate response body for pass/fail.
		var body []byte
		getDetails := func() ([]byte, error) {
			proxyRequest, errProxy := framework.GetServicesProxyRequest(f.Client, f.Client.Get())
			if errProxy != nil {
				return nil, errProxy
			}
			return proxyRequest.Namespace(f.Namespace.Name).
				Name(svc.Name).
				Suffix("read").
				DoRaw()
		}

		getStatus := func() ([]byte, error) {
			proxyRequest, errProxy := framework.GetServicesProxyRequest(f.Client, f.Client.Get())
			if errProxy != nil {
				return nil, errProxy
			}
			return proxyRequest.Namespace(f.Namespace.Name).
				Name(svc.Name).
				Suffix("status").
				DoRaw()
		}

		// nettest containers will wait for all service endpoints to come up for 2 minutes
		// apply a 3 minutes observation period here to avoid this test to time out before the nettest starts to contact peers
		timeout := time.Now().Add(3 * time.Minute)
		for i := 0; !passed && timeout.After(time.Now()); i++ {
			time.Sleep(2 * time.Second)
			framework.Logf("About to make a proxy status call")
			start := time.Now()
			body, err = getStatus()
			framework.Logf("Proxy status call returned in %v", time.Since(start))
			if err != nil {
				framework.Logf("Attempt %v: service/pod still starting. (error: '%v')", i, err)
				continue
			}
			// Finally, we pass/fail the test based on if the container's response body, as to whether or not it was able to find peers.
			switch {
			case string(body) == "pass":
				framework.Logf("Passed on attempt %v. Cleaning up.", i)
				passed = true
			case string(body) == "running":
				framework.Logf("Attempt %v: test still running", i)
			case string(body) == "fail":
				if body, err = getDetails(); err != nil {
					framework.Failf("Failed on attempt %v. Cleaning up. Error reading details: %v", i, err)
				} else {
					framework.Failf("Failed on attempt %v. Cleaning up. Details:\n%s", i, string(body))
				}
			case strings.Contains(string(body), "no endpoints available"):
				framework.Logf("Attempt %v: waiting on service/endpoints", i)
			default:
				framework.Logf("Unexpected response:\n%s", body)
			}
		}

		if !passed {
			if body, err = getDetails(); err != nil {
				framework.Failf("Timed out. Cleaning up. Error reading details: %v", err)
			} else {
				framework.Failf("Timed out. Cleaning up. Details:\n%s", string(body))
			}
		}
		Expect(string(body)).To(Equal("pass"))
	})

	framework.KubeDescribe("Granular Checks", func() {

		It("should function for pod communication on a single node", func() {

			By("Picking a node")
			nodes, err := framework.GetReadyNodes(f)
			framework.ExpectNoError(err)
			node := nodes.Items[0]

			By("Creating a webserver pod")
			podName := "same-node-webserver"
			defer f.Client.Pods(f.Namespace.Name).Delete(podName, nil)
			ip := framework.LaunchWebserverPod(f, podName, node.Name)

			By("Checking that the webserver is accessible from a pod on the same node")
			framework.ExpectNoError(framework.CheckConnectivityToHost(f, node.Name, "same-node-wget", ip))
		})

		It("should function for pod communication between nodes", func() {

			podClient := f.Client.Pods(f.Namespace.Name)

			By("Picking multiple nodes")
			nodes, err := framework.GetReadyNodes(f)
			framework.ExpectNoError(err)

			if len(nodes.Items) == 1 {
				framework.Skipf("The test requires two Ready nodes on %s, but found just one.", framework.TestContext.Provider)
			}

			node1 := nodes.Items[0]
			node2 := nodes.Items[1]

			By("Creating a webserver pod")
			podName := "different-node-webserver"
			defer podClient.Delete(podName, nil)
			ip := framework.LaunchWebserverPod(f, podName, node1.Name)

			By("Checking that the webserver is accessible from a pod on a different node")
			framework.ExpectNoError(framework.CheckConnectivityToHost(f, node2.Name, "different-node-wget", ip))
		})
	})
})

func LaunchNetTestPodPerNode(f *framework.Framework, nodes *api.NodeList, name, version string) []string {
	podNames := []string{}

	totalPods := len(nodes.Items)

	Expect(totalPods).NotTo(Equal(0))

	for _, node := range nodes.Items {
		pod, err := f.Client.Pods(f.Namespace.Name).Create(&api.Pod{
			ObjectMeta: api.ObjectMeta{
				GenerateName: name + "-",
				Labels: map[string]string{
					"name": name,
				},
			},
			Spec: api.PodSpec{
				Containers: []api.Container{
					{
						Name:  "webserver",
						Image: "gcr.io/google_containers/nettest:" + version,
						Args: []string{
							"-service=" + name,
							//peers >= totalPods should be asserted by the container.
							//the nettest container finds peers by looking up list of svc endpoints.
							fmt.Sprintf("-peers=%d", totalPods),
							"-namespace=" + f.Namespace.Name},
						Ports: []api.ContainerPort{{ContainerPort: 8080}},
					},
				},
				NodeName:      node.Name,
				RestartPolicy: api.RestartPolicyNever,
			},
		})
		Expect(err).NotTo(HaveOccurred())
		framework.Logf("Created pod %s on node %s", pod.ObjectMeta.Name, node.Name)
		podNames = append(podNames, pod.ObjectMeta.Name)
	}
	return podNames
}
<|endoftext|>


<commit_before>package cmd

import (
	"github.com/spf13/cobra"
	"os"
)

// completionCmd represents the completion command
var completionCmd = &cobra.Command{
	Use:   "completion",
	Short: "generate completion script",
}

var completionBashCmd = &cobra.Command{
	Use: "bash",
	Short: "generate bash completion script",
	Run: func(cmd *cobra.Command, args []string) {
		RootCmd.GenBashCompletion(os.Stdout)
	},
}

func init() {
	RootCmd.AddCommand(completionCmd)
	completionCmd.AddCommand(completionBashCmd)
}
<commit_msg>add zsh completion<commit_after>package cmd

import (
	"fmt"
	"github.com/spf13/cobra"
	"os"
)

// completionCmd represents the completion command
var completionCmd = &cobra.Command{
	Use:   "completion",
	Short: "generate completion script",
}

var completionBashCmd = &cobra.Command{
	Use:   "bash",
	Short: "generate bash completion script",
	Run: func(cmd *cobra.Command, args []string) {
		RootCmd.GenBashCompletion(os.Stdout)
	},
}

// Refs
// - https://github.com/kubernetes/kubernetes/blob/master/pkg/kubectl/cmd/completion.go
// - https://github.com/spf13/cobra/issues/107#issuecomment-270140429
var completionZshCmd = &cobra.Command{
	Use:   "zsh",
	Short: "generate zsh completion script",
	Run: func(cmd *cobra.Command, args []string) {
		zshHead := "#compdef todoist"
		zshInitialization := `
__todoist_bash_source() {
	alias shopt=':'
	alias _expand=_bash_expand
	alias _complete=_bash_comp
	emulate -L sh
	setopt kshglob noshglob braceexpand
	source "$@"
}

__todoist_type() {
	# -t is not supported by zsh
	if [ "$1" == "-t" ]; then
		shift
		# fake Bash 4 to disable "complete -o nospace". Instead
		# "compopt +-o nospace" is used in the code to toggle trailing
		# spaces. We don't support that, but leave trailing spaces on
		# all the time
		if [ "$1" = "__todoist_compopt" ]; then
			echo builtin
			return 0
		fi
	fi
	type "$@"
}

__todoist_compgen() {
	local completions w
	completions=( $(compgen "$@") ) || return $?
	# filter by given word as prefix
	while [[ "$1" = -* && "$1" != -- ]]; do
		shift
		shift
	done
	if [[ "$1" == -- ]]; then
		shift
	fi
	for w in "${completions[@]}"; do
		if [[ "${w}" = "$1"* ]]; then
			echo "${w}"
		fi
	done
}

__todoist_compopt() {
	true # don't do anything. Not supported by bashcompinit in zsh
}

__todoist_ltrim_colon_completions()
{
	if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then
		# Remove colon-word prefix from COMPREPLY items
		local colon_word=${1%${1##*:}}
		local i=${#COMPREPLY[*]}
		while [[ $((--i)) -ge 0 ]]; do
			COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"}
		done
	fi
}

__todoist_get_comp_words_by_ref() {
	cur="${COMP_WORDS[COMP_CWORD]}"
	prev="${COMP_WORDS[${COMP_CWORD}-1]}"
	words=("${COMP_WORDS[@]}")
	cword=("${COMP_CWORD[@]}")
}

__todoist_filedir() {
	local RET OLD_IFS w qw
	__todoist_debug "_filedir $@ cur=$cur"
	if [[ "$1" = \~* ]]; then
		# somehow does not work. Maybe, zsh does not call this at all
		eval echo "$1"
		return 0
	fi
	OLD_IFS="$IFS"
	IFS=$'\n'
	if [ "$1" = "-d" ]; then
		shift
		RET=( $(compgen -d) )
	else
		RET=( $(compgen -f) )
	fi
	IFS="$OLD_IFS"
	IFS="," __todoist_debug "RET=${RET[@]} len=${#RET[@]}"
	for w in ${RET[@]}; do
		if [[ ! "${w}" = "${cur}"* ]]; then
			continue
		fi
		if eval "[[ \"\${w}\" = *.$1 || -d \"\${w}\" ]]"; then
			qw="$(__todoist_quote "${w}")"
			if [ -d "${w}" ]; then
				COMPREPLY+=("${qw}/")
			else
				COMPREPLY+=("${qw}")
			fi
		fi
	done
}

__todoist_quote() {
    if [[ $1 == \'* || $1 == \"* ]]; then
        # Leave out first character
        printf %q "${1:1}"
    else
		printf %q "$1"
    fi
}

autoload -U +X bashcompinit && bashcompinit

# use word boundary patterns for BSD or GNU sed
LWORD='[[:<:]]'
RWORD='[[:>:]]'
if sed --help 2>&1 | grep -q GNU; then
	LWORD='\<'
	RWORD='\>'
fi

__todoist_convert_bash_to_zsh() {
	sed \
	-e 's/declare -F/whence -w/' \
	-e 's/_get_comp_words_by_ref "\$@"/_get_comp_words_by_ref "\$*"/' \
	-e 's/local \([a-zA-Z0-9_]*\)=/local \1; \1=/' \
	-e 's/flags+=("\(--.*\)=")/flags+=("\1"); two_word_flags+=("\1")/' \
	-e 's/must_have_one_flag+=("\(--.*\)=")/must_have_one_flag+=("\1")/' \
	-e "s/${LWORD}_filedir${RWORD}/__todoist_filedir/g" \
	-e "s/${LWORD}_get_comp_words_by_ref${RWORD}/__todoist_get_comp_words_by_ref/g" \
	-e "s/${LWORD}__ltrim_colon_completions${RWORD}/__todoist_ltrim_colon_completions/g" \
	-e "s/${LWORD}compgen${RWORD}/__todoist_compgen/g" \
	-e "s/${LWORD}compopt${RWORD}/__todoist_compopt/g" \
	-e "s/${LWORD}declare${RWORD}/builtin declare/g" \
	-e "s/\\\$(type${RWORD}/\$(__todoist_type/g" \
	<<'BASH_COMPLETION_EOF'
`
		zshTail := `
BASH_COMPLETION_EOF
}
__todoist_bash_source <(__todoist_convert_bash_to_zsh)
_complete todoist 2>/dev/null
`
		fmt.Println(zshHead)
		fmt.Print(zshInitialization)
		RootCmd.GenBashCompletion(os.Stdout)
		fmt.Print(zshTail)
	},
}

func init() {
	RootCmd.AddCommand(completionCmd)
	completionCmd.AddCommand(completionBashCmd)
	completionCmd.AddCommand(completionZshCmd)
}
<|endoftext|>


<commit_before>package server

import (
	"sync"

	"github.com/tidwall/expr"
	"github.com/tidwall/geojson"
	"github.com/tidwall/gjson"
	"github.com/tidwall/tile38/internal/field"
	"github.com/tidwall/tile38/internal/object"
)

type exprPool struct {
	pool *sync.Pool
}

func typeForObject(o *object.Object) expr.Value {
	switch o.Geo().(type) {
	case *geojson.Point, *geojson.SimplePoint:
		return expr.String("Point")
	case *geojson.LineString:
		return expr.String("LineString")
	case *geojson.Polygon, *geojson.Circle, *geojson.Rect:
		return expr.String("Polygon")
	case *geojson.MultiPoint:
		return expr.String("MultiPoint")
	case *geojson.MultiLineString:
		return expr.String("MultiLineString")
	case *geojson.MultiPolygon:
		return expr.String("MultiPolygon")
	case *geojson.GeometryCollection:
		return expr.String("GeometryCollection")
	case *geojson.Feature:
		return expr.String("Feature")
	case *geojson.FeatureCollection:
		return expr.String("FeatureCollection")
	default:
		return expr.Undefined
	}
}

func resultToValue(r gjson.Result) expr.Value {
	if !r.Exists() {
		return expr.Undefined
	}
	switch r.Type {
	case gjson.String:
		return expr.String(r.String())
	case gjson.False:
		return expr.Bool(false)
	case gjson.True:
		return expr.Bool(true)
	case gjson.Number:
		return expr.Number(r.Float())
	case gjson.JSON:
		return expr.String(r.String())
	default:
		return expr.Null
	}
}

func newExprPool(s *Server) *exprPool {
	ext := expr.NewExtender(
		// ref
		func(info expr.RefInfo, ctx *expr.Context) (expr.Value, error) {
			o := ctx.UserData.(*object.Object)
			if !info.Chain {
				// root
				if r := gjson.Get(o.Geo().Members(), info.Ident); r.Exists() {
					return resultToValue(r), nil
				}
				switch info.Ident {
				case "id":
					return expr.String(o.ID()), nil
				case "type":
					return typeForObject(o), nil
				default:
					var rf field.Field
					var ok bool
					o.Fields().Scan(func(f field.Field) bool {
						if f.Name() == info.Ident {
							rf = f
							ok = true
							return false
						}
						return true
					})
					if ok {
						r := gjson.Parse(rf.Value().JSON())
						return resultToValue(r), nil
					}
				}
			} else {
				switch info.Value.Value().(type) {
				case string:
					r := gjson.Get(info.Value.String(), info.Ident)
					return resultToValue(r), nil
				}
			}
			return expr.Undefined, nil
		},
		// call
		func(info expr.CallInfo, ctx *expr.Context) (expr.Value, error) {
			// No custom calls
			return expr.Undefined, nil
		},
		// op
		func(info expr.OpInfo, ctx *expr.Context) (expr.Value, error) {
			// No custom operations
			return expr.Undefined, nil
		},
	)
	return &exprPool{
		pool: &sync.Pool{
			New: func() any {
				ctx := &expr.Context{
					Extender: ext,
				}
				return ctx
			},
		},
	}
}

func (p *exprPool) Get(o *object.Object) *expr.Context {
	ctx := p.pool.Get().(*expr.Context)
	ctx.UserData = o
	return ctx
}

func (p *exprPool) Put(ctx *expr.Context) {
	p.pool.Put(ctx)
}

func (where whereT) matchExpr(s *Server, o *object.Object) bool {
	ctx := s.epool.Get(o)
	res, _ := expr.Eval(where.name, ctx)
	s.epool.Put(ctx)
	return res.Bool()
}
<commit_msg>Add match method to expressions<commit_after>package server

import (
	"sync"

	"github.com/tidwall/expr"
	"github.com/tidwall/geojson"
	"github.com/tidwall/gjson"
	"github.com/tidwall/match"
	"github.com/tidwall/tile38/internal/field"
	"github.com/tidwall/tile38/internal/object"
)

type exprPool struct {
	pool *sync.Pool
}

func typeForObject(o *object.Object) expr.Value {
	switch o.Geo().(type) {
	case *geojson.Point, *geojson.SimplePoint:
		return expr.String("Point")
	case *geojson.LineString:
		return expr.String("LineString")
	case *geojson.Polygon, *geojson.Circle, *geojson.Rect:
		return expr.String("Polygon")
	case *geojson.MultiPoint:
		return expr.String("MultiPoint")
	case *geojson.MultiLineString:
		return expr.String("MultiLineString")
	case *geojson.MultiPolygon:
		return expr.String("MultiPolygon")
	case *geojson.GeometryCollection:
		return expr.String("GeometryCollection")
	case *geojson.Feature:
		return expr.String("Feature")
	case *geojson.FeatureCollection:
		return expr.String("FeatureCollection")
	default:
		return expr.Undefined
	}
}

func resultToValue(r gjson.Result) expr.Value {
	if !r.Exists() {
		return expr.Undefined
	}
	switch r.Type {
	case gjson.String:
		return expr.String(r.String())
	case gjson.False:
		return expr.Bool(false)
	case gjson.True:
		return expr.Bool(true)
	case gjson.Number:
		return expr.Number(r.Float())
	case gjson.JSON:
		return expr.Object(r)
	default:
		return expr.Null
	}
}

func newExprPool(s *Server) *exprPool {
	ext := expr.NewExtender(
		// ref
		func(info expr.RefInfo, ctx *expr.Context) (expr.Value, error) {
			o := ctx.UserData.(*object.Object)
			if !info.Chain {
				// root
				if r := gjson.Get(o.Geo().Members(), info.Ident); r.Exists() {
					return resultToValue(r), nil
				}
				switch info.Ident {
				case "id":
					return expr.String(o.ID()), nil
				case "type":
					return typeForObject(o), nil
				default:
					var rf field.Field
					var ok bool
					o.Fields().Scan(func(f field.Field) bool {
						if f.Name() == info.Ident {
							rf = f
							ok = true
							return false
						}
						return true
					})
					if ok {
						r := gjson.Parse(rf.Value().JSON())
						return resultToValue(r), nil
					}
				}
			} else {
				switch v := info.Value.Value().(type) {
				case gjson.Result:
					return resultToValue(v.Get(info.Ident)), nil
				default:
					// object methods
					switch info.Ident {
					case "match":
						return expr.Function("match"), nil
					}
				}
			}
			return expr.Undefined, nil
		},
		// call
		func(info expr.CallInfo, ctx *expr.Context) (expr.Value, error) {
			if info.Chain {
				switch info.Ident {
				case "match":
					args, err := info.Args.Compute()
					if err != nil {
						return expr.Undefined, err
					}
					t := match.Match(info.Value.String(), args.Get(0).String())
					return expr.Bool(t), nil
				}
			}
			return expr.Undefined, nil
		},
		// op
		func(info expr.OpInfo, ctx *expr.Context) (expr.Value, error) {
			// No custom operations
			return expr.Undefined, nil
		},
	)
	return &exprPool{
		pool: &sync.Pool{
			New: func() any {
				ctx := &expr.Context{
					Extender: ext,
				}
				return ctx
			},
		},
	}
}

func (p *exprPool) Get(o *object.Object) *expr.Context {
	ctx := p.pool.Get().(*expr.Context)
	ctx.UserData = o
	return ctx
}

func (p *exprPool) Put(ctx *expr.Context) {
	p.pool.Put(ctx)
}

func (where whereT) matchExpr(s *Server, o *object.Object) bool {
	ctx := s.epool.Get(o)
	res, _ := expr.Eval(where.name, ctx)
	s.epool.Put(ctx)
	return res.Bool()
}
<|endoftext|>


<commit_before>// Package strmangle is used exclusively by the templates in sqlboiler.
// There are many helper functions to deal with bdb.* values as well
// as string manipulation. Because it is focused on pipelining inside templates
// you will see some odd parameter ordering.
package strmangle

import (
	"fmt"
	"math"
	"regexp"
	"strings"

	"github.com/jinzhu/inflection"
)

var (
	idAlphabet     = []byte("abcdefghijklmnopqrstuvwxyz")
	uppercaseWords = []*regexp.Regexp{
		regexp.MustCompile(`^id[0-9]*$`),
		regexp.MustCompile(`^uid[0-9]*$`),
		regexp.MustCompile(`^uuid[0-9]*$`),
		regexp.MustCompile(`^guid[0-9]*$`),
		regexp.MustCompile(`^ssn[0-9]*$`),
		regexp.MustCompile(`^tz[0-9]*$`),
	}
	smartQuoteRgx = regexp.MustCompile(`^(?i)"?[a-z_][_a-z0-9]*"?(\."?[_a-z][_a-z0-9]*"?)*$`)
)

// IdentQuote attempts to quote simple identifiers in SQL tatements
func IdentQuote(s string) string {
	if s == "null" {
		return s
	}

	if m := smartQuoteRgx.MatchString(s); m != true {
		return s
	}

	splits := strings.Split(s, ".")
	for i, split := range splits {
		if strings.HasPrefix(split, `"`) || strings.HasSuffix(split, `"`) {
			continue
		}

		splits[i] = fmt.Sprintf(`"%s"`, split)
	}

	return strings.Join(splits, ".")
}

// Identifier is a base conversion from Base 10 integers to Base 26
// integers that are represented by an alphabet from a-z
// See tests for example outputs.
func Identifier(in int) string {
	ln := len(idAlphabet)
	var n int
	if in == 0 {
		n = 1
	} else {
		n = 1 + int(math.Log(float64(in))/math.Log(float64(ln)))
	}

	cols := make([]byte, n)

	for i := 0; i < n; i++ {
		divisor := int(math.Pow(float64(ln), float64(n-i-1)))
		rem := in / divisor
		cols[i] = idAlphabet[rem]

		in -= rem * divisor
	}

	return string(cols)
}

// Plural converts singular words to plural words (eg: person to people)
func Plural(name string) string {
	splits := strings.Split(name, "_")
	splits[len(splits)-1] = inflection.Plural(splits[len(splits)-1])
	return strings.Join(splits, "_")
}

// Singular converts plural words to singular words (eg: people to person)
func Singular(name string) string {
	splits := strings.Split(name, "_")
	splits[len(splits)-1] = inflection.Singular(splits[len(splits)-1])
	return strings.Join(splits, "_")
}

// TitleCase changes a snake-case variable name
// into a go styled object variable name of "ColumnName".
// titleCase also fully uppercases "ID" components of names, for example
// "column_name_id" to "ColumnNameID".
func TitleCase(name string) string {
	splits := strings.Split(name, "_")

	for i, split := range splits {
		found := false
		for _, uc := range uppercaseWords {
			if uc.MatchString(split) {
				splits[i] = strings.ToUpper(split)
				found = true
				break
			}
		}

		if found {
			continue
		}

		splits[i] = strings.Title(split)
	}

	return strings.Join(splits, "")
}

// CamelCase takes a variable name in the format of "var_name" and converts
// it into a go styled variable name of "varName".
// camelCase also fully uppercases "ID" components of names, for example
// "var_name_id" to "varNameID".
func CamelCase(name string) string {
	splits := strings.Split(name, "_")

	for i, split := range splits {
		if i == 0 {
			continue
		}

		found := false
		if i > 0 {
			for _, uc := range uppercaseWords {
				if uc.MatchString(split) {
					splits[i] = strings.ToUpper(split)
					found = true
					break
				}
			}
		}

		if found {
			continue
		}

		splits[i] = strings.Title(split)
	}

	return strings.Join(splits, "")
}

// MakeStringMap converts a map[string]string into the format:
// "key": "value", "key": "value"
func MakeStringMap(types map[string]string) string {
	var typArr []string
	for k, v := range types {
		typArr = append(typArr, fmt.Sprintf(`"%s": "%s"`, k, v))
	}

	return strings.Join(typArr, ", ")
}

// StringMap maps a function over a slice of strings.
func StringMap(modifier func(string) string, strs []string) []string {
	ret := make([]string, len(strs))

	for i, str := range strs {
		ret[i] = modifier(str)
	}

	return ret
}

// MakeDBName takes a table name in the format of "table_name" and a
// column name in the format of "column_name" and returns a name used in the
// `db:""` component of an object in the format of "table_name_column_name"
func MakeDBName(tableName, colName string) string {
	return fmt.Sprintf("%s_%s", tableName, colName)
}

// HasElement checks to see if the string is found in the string slice
func HasElement(str string, slice []string) bool {
	for _, s := range slice {
		if str == s {
			return true
		}
	}

	return false
}

// PrefixStringSlice with the given str.
func PrefixStringSlice(str string, strs []string) []string {
	ret := make([]string, len(strs))

	for i, s := range strs {
		ret[i] = fmt.Sprintf("%s%s", str, s)
	}

	return ret
}

// GenerateParamFlags generates the SQL statement parameter flags
// For example, $1,$2,$3 etc. It will start counting at startAt.
func GenerateParamFlags(colCount int, startAt int) string {
	cols := make([]string, 0, colCount)

	for i := startAt; i < colCount+startAt; i++ {
		cols = append(cols, fmt.Sprintf("$%d", i))
	}

	return strings.Join(cols, ",")
}

// WhereClause returns the where clause using start as the $ flag index
// For example, if start was 2 output would be: "colthing=$2 AND colstuff=$3"
func WhereClause(cols []string, start int) string {
	if start == 0 {
		panic("0 is not a valid start number for whereClause")
	}

	ret := make([]string, len(cols))
	for i, c := range cols {
		ret[i] = fmt.Sprintf(`"%s"=$%d`, c, start+i)
	}

	return strings.Join(ret, " AND ")
}

// DriverUsesLastInsertID returns whether the database driver supports the
// sql.Result interface.
func DriverUsesLastInsertID(driverName string) bool {
	switch driverName {
	case "postgres":
		return false
	default:
		return true
	}
}

// Substring returns a substring of str starting at index start and going
// to end-1.
func Substring(start, end int, str string) string {
	return str[start:end]
}

// JoinSlices merges two string slices of equal length
func JoinSlices(sep string, a, b []string) []string {
	lna, lnb := len(a), len(b)
	if lna != lnb {
		panic("joinSlices: can only merge slices of same length")
	} else if lna == 0 {
		return nil
	}

	ret := make([]string, len(a))
	for i, elem := range a {
		ret[i] = fmt.Sprintf("%s%s%s", elem, sep, b[i])
	}

	return ret
}
<commit_msg>Fix silly regexp pattern<commit_after>// Package strmangle is used exclusively by the templates in sqlboiler.
// There are many helper functions to deal with bdb.* values as well
// as string manipulation. Because it is focused on pipelining inside templates
// you will see some odd parameter ordering.
package strmangle

import (
	"fmt"
	"math"
	"regexp"
	"strings"

	"github.com/jinzhu/inflection"
)

var (
	idAlphabet     = []byte("abcdefghijklmnopqrstuvwxyz")
	uppercaseWords = regexp.MustCompile(`^(?i)(id|uid|uuid|guid|ssn|tz)[0-9]*$`)
	smartQuoteRgx  = regexp.MustCompile(`^(?i)"?[a-z_][_a-z0-9]*"?(\."?[_a-z][_a-z0-9]*"?)*$`)
)

// IdentQuote attempts to quote simple identifiers in SQL tatements
func IdentQuote(s string) string {
	if s == "null" {
		return s
	}

	if m := smartQuoteRgx.MatchString(s); m != true {
		return s
	}

	splits := strings.Split(s, ".")
	for i, split := range splits {
		if strings.HasPrefix(split, `"`) || strings.HasSuffix(split, `"`) {
			continue
		}

		splits[i] = fmt.Sprintf(`"%s"`, split)
	}

	return strings.Join(splits, ".")
}

// Identifier is a base conversion from Base 10 integers to Base 26
// integers that are represented by an alphabet from a-z
// See tests for example outputs.
func Identifier(in int) string {
	ln := len(idAlphabet)
	var n int
	if in == 0 {
		n = 1
	} else {
		n = 1 + int(math.Log(float64(in))/math.Log(float64(ln)))
	}

	cols := make([]byte, n)

	for i := 0; i < n; i++ {
		divisor := int(math.Pow(float64(ln), float64(n-i-1)))
		rem := in / divisor
		cols[i] = idAlphabet[rem]

		in -= rem * divisor
	}

	return string(cols)
}

// Plural converts singular words to plural words (eg: person to people)
func Plural(name string) string {
	splits := strings.Split(name, "_")
	splits[len(splits)-1] = inflection.Plural(splits[len(splits)-1])
	return strings.Join(splits, "_")
}

// Singular converts plural words to singular words (eg: people to person)
func Singular(name string) string {
	splits := strings.Split(name, "_")
	splits[len(splits)-1] = inflection.Singular(splits[len(splits)-1])
	return strings.Join(splits, "_")
}

// TitleCase changes a snake-case variable name
// into a go styled object variable name of "ColumnName".
// titleCase also fully uppercases "ID" components of names, for example
// "column_name_id" to "ColumnNameID".
func TitleCase(name string) string {
	splits := strings.Split(name, "_")

	for i, split := range splits {
		if uppercaseWords.MatchString(split) {
			splits[i] = strings.ToUpper(split)
			continue
		}

		splits[i] = strings.Title(split)
	}

	return strings.Join(splits, "")
}

// CamelCase takes a variable name in the format of "var_name" and converts
// it into a go styled variable name of "varName".
// camelCase also fully uppercases "ID" components of names, for example
// "var_name_id" to "varNameID".
func CamelCase(name string) string {
	splits := strings.Split(name, "_")

	for i, split := range splits {
		if i == 0 {
			continue
		}

		if i > 0 {
			if uppercaseWords.MatchString(split) {
				splits[i] = strings.ToUpper(split)
				continue
			}
		}

		splits[i] = strings.Title(split)
	}

	return strings.Join(splits, "")
}

// MakeStringMap converts a map[string]string into the format:
// "key": "value", "key": "value"
func MakeStringMap(types map[string]string) string {
	var typArr []string
	for k, v := range types {
		typArr = append(typArr, fmt.Sprintf(`"%s": "%s"`, k, v))
	}

	return strings.Join(typArr, ", ")
}

// StringMap maps a function over a slice of strings.
func StringMap(modifier func(string) string, strs []string) []string {
	ret := make([]string, len(strs))

	for i, str := range strs {
		ret[i] = modifier(str)
	}

	return ret
}

// MakeDBName takes a table name in the format of "table_name" and a
// column name in the format of "column_name" and returns a name used in the
// `db:""` component of an object in the format of "table_name_column_name"
func MakeDBName(tableName, colName string) string {
	return fmt.Sprintf("%s_%s", tableName, colName)
}

// HasElement checks to see if the string is found in the string slice
func HasElement(str string, slice []string) bool {
	for _, s := range slice {
		if str == s {
			return true
		}
	}

	return false
}

// PrefixStringSlice with the given str.
func PrefixStringSlice(str string, strs []string) []string {
	ret := make([]string, len(strs))

	for i, s := range strs {
		ret[i] = fmt.Sprintf("%s%s", str, s)
	}

	return ret
}

// GenerateParamFlags generates the SQL statement parameter flags
// For example, $1,$2,$3 etc. It will start counting at startAt.
func GenerateParamFlags(colCount int, startAt int) string {
	cols := make([]string, 0, colCount)

	for i := startAt; i < colCount+startAt; i++ {
		cols = append(cols, fmt.Sprintf("$%d", i))
	}

	return strings.Join(cols, ",")
}

// WhereClause returns the where clause using start as the $ flag index
// For example, if start was 2 output would be: "colthing=$2 AND colstuff=$3"
func WhereClause(cols []string, start int) string {
	if start == 0 {
		panic("0 is not a valid start number for whereClause")
	}

	ret := make([]string, len(cols))
	for i, c := range cols {
		ret[i] = fmt.Sprintf(`"%s"=$%d`, c, start+i)
	}

	return strings.Join(ret, " AND ")
}

// DriverUsesLastInsertID returns whether the database driver supports the
// sql.Result interface.
func DriverUsesLastInsertID(driverName string) bool {
	switch driverName {
	case "postgres":
		return false
	default:
		return true
	}
}

// Substring returns a substring of str starting at index start and going
// to end-1.
func Substring(start, end int, str string) string {
	return str[start:end]
}

// JoinSlices merges two string slices of equal length
func JoinSlices(sep string, a, b []string) []string {
	lna, lnb := len(a), len(b)
	if lna != lnb {
		panic("joinSlices: can only merge slices of same length")
	} else if lna == 0 {
		return nil
	}

	ret := make([]string, len(a))
	for i, elem := range a {
		ret[i] = fmt.Sprintf("%s%s%s", elem, sep, b[i])
	}

	return ret
}
<|endoftext|>


<commit_before>
package amzses

import (
	"os"
	"crypto/hmac"
	"encoding/base64"
	"fmt"
	"github.com/stathat/jconfig"
	"io/ioutil"
	"log"
	"http"
	"url"
	"time"
)

const (
	endpoint = "https://email.us-east-1.amazonaws.com"
)

var accessKey, secretKey string

func init() {
	config := jconfig.LoadConfig("/etc/aws.conf")
	accessKey = config.GetString("aws_access_key")
	secretKey = config.GetString("aws_secret_key")
}

func SendMail(from, to, subject, text, html string) (string, os.Error) {
	data := make(url.Values)
	data.Add("Action", "SendEmail")
	data.Add("Source", from)
	data.Add("Destination.ToAddresses.member.1", to)
	data.Add("Message.Subject.Data", subject)
	data.Add("Message.Body.Text.Data", text)
	data.Add("Message.Body.Html.Data", html)
	data.Add("AWSAccessKeyId", accessKey)

	return sesGet(data)
}

func authorizationHeader(date string) []string {
	h := hmac.NewSHA256([]uint8(secretKey))
	h.Write([]uint8(date))
	signature := base64.StdEncoding.EncodeToString(h.Sum())
	auth := fmt.Sprintf("AWS3-HTTPS AWSAccessKeyId=%s, Algorithm=HmacSHA256, Signature=%s", accessKey, signature)
	return []string{auth}
}

func sesGet(data url.Values) (string, os.Error) {
	urlstr := fmt.Sprintf("%s?%s", endpoint, data.Encode())
	endpointURL, _ := url.Parse(urlstr)
	headers := map[string][]string{}

	now := time.UTC()
	// date format: "Tue, 25 May 2010 21:20:27 +0000"
	date := now.Format("Mon, 02 Jan 2006 15:04:05 -0700")
	headers["Date"] = []string{date}

	h := hmac.NewSHA256([]uint8(secretKey))
	h.Write([]uint8(date))
	signature := base64.StdEncoding.EncodeToString(h.Sum())
	auth := fmt.Sprintf("AWS3-HTTPS AWSAccessKeyId=%s, Algorithm=HmacSHA256, Signature=%s", accessKey, signature)
	headers["X-Amzn-Authorization"] = []string{auth}

	req := http.Request{
		URL:        endpointURL,
		Method:     "GET",
		ProtoMajor: 1,
		ProtoMinor: 1,
		Close:      true,
		Header:     headers,
	}

	r, err := http.DefaultClient.Do(&req)
	if err != nil {
		log.Printf("http error: %s", err)
		return "", err
	}

	resultbody, _ := ioutil.ReadAll(r.Body)
	r.Body.Close()

	if r.StatusCode != 200 {
		log.Printf("error, status = %d", r.StatusCode)

		log.Printf("error response: %s", resultbody)
		return "", os.NewError(string(resultbody))
	}

	return string(resultbody), nil
}
<commit_msg>get aws.conf in current dir<commit_after>
package amzses

import (
	"os"
	"crypto/hmac"
	"encoding/base64"
	"fmt"
	"github.com/stathat/jconfig"
	"io/ioutil"
	"log"
	"http"
	"url"
	"time"
)

const (
	endpoint = "https://email.us-east-1.amazonaws.com"
)

var accessKey, secretKey string

func init() {
	config := jconfig.LoadConfig("aws.conf")
	accessKey = config.GetString("aws_access_key")
	secretKey = config.GetString("aws_secret_key")
}

func SendMail(from, to, subject, text, html string) (string, os.Error) {
	data := make(url.Values)
	data.Add("Action", "SendEmail")
	data.Add("Source", from)
	data.Add("Destination.ToAddresses.member.1", to)
	data.Add("Message.Subject.Data", subject)
	data.Add("Message.Body.Text.Data", text)
	data.Add("Message.Body.Html.Data", html)
	data.Add("AWSAccessKeyId", accessKey)

	return sesGet(data)
}

func authorizationHeader(date string) []string {
	h := hmac.NewSHA256([]uint8(secretKey))
	h.Write([]uint8(date))
	signature := base64.StdEncoding.EncodeToString(h.Sum())
	auth := fmt.Sprintf("AWS3-HTTPS AWSAccessKeyId=%s, Algorithm=HmacSHA256, Signature=%s", accessKey, signature)
	return []string{auth}
}

func sesGet(data url.Values) (string, os.Error) {
	urlstr := fmt.Sprintf("%s?%s", endpoint, data.Encode())
	endpointURL, _ := url.Parse(urlstr)
	headers := map[string][]string{}

	now := time.UTC()
	// date format: "Tue, 25 May 2010 21:20:27 +0000"
	date := now.Format("Mon, 02 Jan 2006 15:04:05 -0700")
	headers["Date"] = []string{date}

	h := hmac.NewSHA256([]uint8(secretKey))
	h.Write([]uint8(date))
	signature := base64.StdEncoding.EncodeToString(h.Sum())
	auth := fmt.Sprintf("AWS3-HTTPS AWSAccessKeyId=%s, Algorithm=HmacSHA256, Signature=%s", accessKey, signature)
	headers["X-Amzn-Authorization"] = []string{auth}

	req := http.Request{
		URL:        endpointURL,
		Method:     "GET",
		ProtoMajor: 1,
		ProtoMinor: 1,
		Close:      true,
		Header:     headers,
	}

	r, err := http.DefaultClient.Do(&req)
	if err != nil {
		log.Printf("http error: %s", err)
		return "", err
	}

	resultbody, _ := ioutil.ReadAll(r.Body)
	r.Body.Close()

	if r.StatusCode != 200 {
		log.Printf("error, status = %d", r.StatusCode)

		log.Printf("error response: %s", resultbody)
		return "", os.NewError(string(resultbody))
	}

	return string(resultbody), nil
}
<|endoftext|>


<commit_before>package f5

import (
	"fmt"
	"strings"
)

// Cluster Management REST paths.
const (
	PathDeviceInfo = "/mgmt/tm/cm/device"
)

// IsActive returns true whether the BigIP is active and the iControl REST are
// accessible. In case of error, false is returned.
func (c *Client) IsActive(host string) bool {
	var respData struct {
		FailoverState string `json:"failoverState"`
	}
	if err := c.ReadQuery(PathDeviceInfo+"/"+host, &respData); err != nil {
		return false
	}
	return respData.FailoverState == "active"
}

// FailoverState returns the status of the BigIP (active, standby,
// forced-offline, ...).
func (c *Client) FailoverState(host, ip string) (string, error) {
	var respData struct {
		Items []struct {
			FailoverState string `json:"failoverState"`
			Name          string `json:"name"`
			Hostname      string `json:"hostname"`
			IP            string `json:"managementIp"`
		} `json:"items"`
	}
	if err := c.ReadQuery(PathDeviceInfo, &respData); err != nil {
		return "unreachable", fmt.Errorf("cannot retrieve failover state: %v", err)
	}
	for _, item := range respData.Items {
		if strings.HasPrefix(item.Name, host) || strings.HasPrefix(item.Hostname, host) {
			if item.FailoverState == "" {
				return "invalid", nil
			}
			return item.FailoverState, nil
		}
	}
	if ip != "" {
		if pos := strings.Index(ip, "/"); pos != -1 {
			ip = ip[:pos]
		}
		for _, item := range respData.Items {
			if strings.HasPrefix(item.IP, ip) {
				if item.FailoverState == "" {
					return "invalid", nil
				}
				return item.FailoverState, nil
			}
		}
	}
	return "invalid hostname", fmt.Errorf("hostname %q and management ip %q mismatch the ones retrieved", host, ip)
}
<commit_msg>f5: add support for sync status retrieval<commit_after>package f5

import (
	"fmt"
	"strings"
)

// Cluster Management REST paths.
const (
	PathDeviceInfo = "/mgmt/tm/cm/device"
	PathSyncStatus = "/mgmt/tm/cm/sync-status"
)

// IsActive returns true whether the BigIP is active and the iControl REST are
// accessible. In case of error, false is returned.
func (c *Client) IsActive(host string) bool {
	var respData struct {
		FailoverState string `json:"failoverState"`
	}
	if err := c.ReadQuery(PathDeviceInfo+"/"+host, &respData); err != nil {
		return false
	}
	return respData.FailoverState == "active"
}

// FailoverState returns the status of the BigIP (active, standby,
// forced-offline, ...).
func (c *Client) FailoverState(host, ip string) (string, error) {
	var respData struct {
		Items []struct {
			FailoverState string `json:"failoverState"`
			Name          string `json:"name"`
			Hostname      string `json:"hostname"`
			IP            string `json:"managementIp"`
		} `json:"items"`
	}
	if err := c.ReadQuery(PathDeviceInfo, &respData); err != nil {
		return "unreachable", fmt.Errorf("cannot retrieve failover state: %v", err)
	}
	for _, item := range respData.Items {
		if strings.HasPrefix(item.Name, host) || strings.HasPrefix(item.Hostname, host) {
			if item.FailoverState == "" {
				return "invalid", nil
			}
			return item.FailoverState, nil
		}
	}
	if ip != "" {
		if pos := strings.Index(ip, "/"); pos != -1 {
			ip = ip[:pos]
		}
		for _, item := range respData.Items {
			if strings.HasPrefix(item.IP, ip) {
				if item.FailoverState == "" {
					return "invalid", nil
				}
				return item.FailoverState, nil
			}
		}
	}
	return "invalid hostname", fmt.Errorf("hostname %q and management ip %q mismatch the ones retrieved", host, ip)
}

// SSyncStatus returns the sync status of the BIG-IP along with the status
// color.
func (c *Client) SyncStatus() (status string, color string, err error) {
	var data struct {
		Entries struct {
			Entry struct {
				NestedStats struct {
					Entries struct {
						Color struct {
							Description string `json:"description"`
						} `json:"color"`
						Status struct {
							Description string `json:"description"`
						} `json:"status"`
					} `json:"entries"`
				} `json:"nestedStats"`
			} `json:"https://localhost/mgmt/tm/cm/sync-status/0"`
		} `json:"entries"`
	}
	if err := c.ReadQuery(PathSyncStatus, &data); err != nil {
		return "", "", fmt.Errorf("cannot retrieve sync status: %v", err)
	}
	status = data.Entries.Entry.NestedStats.Entries.Status.Description
	color = data.Entries.Entry.NestedStats.Entries.Color.Description
	return
}
<|endoftext|>


<commit_before>// This source file is part of the Packet Guardian project.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package api

import (
	"net"
	"net/http"
	"strings"
	"time"

	"github.com/gorilla/mux"
	"github.com/lfkeitel/verbose"
	"github.com/usi-lfkeitel/packet-guardian/src/common"
	"github.com/usi-lfkeitel/packet-guardian/src/models"
)

type Device struct {
	e *common.Environment
}

func NewDeviceController(e *common.Environment) *Device {
	return &Device{e: e}
}

func (d *Device) RegistrationHandler(w http.ResponseWriter, r *http.Request) {
	// Check authentication and get User models
	var formUser *models.User // The user to whom the device is being registered
	var err error
	sessionUser := models.GetUserFromContext(r)
	formUsername := strings.ToLower(r.FormValue("username"))
	if formUsername == "" {
		common.NewAPIResponse("No username given", nil).WriteResponse(w, http.StatusBadRequest)
		return
	}

	if sessionUser.Username != formUsername && !sessionUser.Can(models.CreateDevice) {
		d.e.Log.Errorf("Admin action attempted: Register device for %s attempted by user %s", formUsername, sessionUser.Username)
		common.NewAPIResponse("Permission denied", nil).WriteResponse(w, http.StatusForbidden)
		return
	}

	if formUsername == sessionUser.Username {
		if !sessionUser.Can(models.CreateOwn) {
			common.NewAPIResponse("Cannot register device - Permission denied", nil).WriteResponse(w, http.StatusForbidden)
			return
		}
		formUser = sessionUser
	} else {
		var err error
		formUser, err = models.GetUserByUsername(d.e, formUsername)
		if err != nil {
			d.e.Log.Errorf("Failed to get user from database %s: %s", formUsername, err.Error())
			common.NewAPIResponse("Error registering device", nil).WriteResponse(w, http.StatusInternalServerError)
			return
		}
	}

	if !sessionUser.Can(models.CreateDevice) {
		if formUser.IsBlacklisted() {
			d.e.Log.Noticef("Attempted registration by blacklisted user %s", formUser.Username)
			common.NewAPIResponse("Username blacklisted", nil).WriteResponse(w, http.StatusForbidden)
			return
		}

		// Get and enforce the device limit
		limit := models.UserDeviceLimit(d.e.Config.Registration.DefaultDeviceLimit)
		if formUser.DeviceLimit != models.UserDeviceLimitGlobal {
			limit = formUser.DeviceLimit
		}

		deviceCount, err := models.GetDeviceCountForUser(d.e, formUser)
		if err != nil {
			d.e.Log.Errorf("Error getting device count: %s", err.Error())
		}
		if limit != models.UserDeviceLimitUnlimited && deviceCount >= int(limit) {
			common.NewAPIResponse("Device limit reached", nil).WriteResponse(w, http.StatusConflict)
			return
		}
	}

	// Get MAC address
	var mac net.HardwareAddr
	macPost := r.FormValue("mac-address")
	manual := (macPost != "")
	ip := net.ParseIP(strings.Split(r.RemoteAddr, ":")[0])
	if manual {
		// Manual registration
		if !d.e.Config.Registration.AllowManualRegistrations {
			d.e.Log.Noticef("Unauthorized manual registration attempt for MAC %s from user %s", macPost, formUser.Username)
			common.NewAPIResponse("Manual registrations not allowed", nil).WriteResponse(w, http.StatusForbidden)
			return
		}
		mac, err = common.FormatMacAddress(macPost)
		if err != nil {
			common.NewAPIResponse("Incorrect MAC address format", nil).WriteResponse(w, http.StatusBadRequest)
			return
		}
	} else {
		// Automatic registration
		lease, err := models.GetLeaseByIP(d.e, ip)
		if err != nil {
			d.e.Log.Errorf("Failed to get MAC for IP %s: %s", ip, err.Error())
			common.NewAPIResponse("Failed detecting MAC address", nil).WriteResponse(w, http.StatusInternalServerError)
			return
		} else if lease.ID == 0 {
			d.e.Log.Errorf("Attempted automatic registration on non-leased device %s", ip)
			common.NewAPIResponse("Error detecting MAC address", nil).WriteResponse(w, http.StatusBadRequest)
			return
		}
		mac = lease.MAC
	}

	// Get device from database
	device, err := models.GetDeviceByMAC(d.e, mac)
	if err != nil {
		d.e.Log.Errorf("Error getting device: %s", err.Error())
		common.NewAPIResponse("Failed loading device", nil).WriteResponse(w, http.StatusInternalServerError)
		return
	}

	// Check if device is already registered
	if device.ID != 0 {
		d.e.Log.Noticef("Attempted duplicate registration of MAC %s to user %s", mac.String(), formUser.Username)
		common.NewAPIResponse("Device already registered", nil).WriteResponse(w, http.StatusConflict)
		return
	}

	// Validate platform, we don't want someone to submit an inappropiate value
	platform := ""
	if manual {
		if common.StringInSlice(r.FormValue("platform"), d.e.Config.Registration.ManualRegPlatforms) {
			platform = r.FormValue("platform")
		}
	} else {
		platform = common.ParseUserAgent(r.UserAgent())
	}

	// Fill in device information
	device.Username = formUser.Username
	device.Description = r.FormValue("description")
	device.RegisteredFrom = ip
	device.Platform = platform
	device.Expires = formUser.DeviceExpiration.NextExpiration(d.e, time.Now())
	device.DateRegistered = time.Now()
	device.LastSeen = time.Now()
	device.UserAgent = r.UserAgent()
	if manual {
		device.UserAgent = "Manual"
	}

	// Save new device
	if err := device.Save(); err != nil {
		d.e.Log.Errorf("Error registering device: %s", err.Error())
		common.NewAPIResponse("Error saving device", nil).WriteResponse(w, http.StatusInternalServerError)
		return
	}
	d.e.Log.Infof("Successfully registered MAC %s to user %s", mac.String(), formUser.Username)

	// Redirect client as needed
	resp := struct{ Location string }{Location: "/manage"}
	if sessionUser.Can(models.ViewDevices) {
		resp.Location = "/admin/manage/" + formUser.Username
	}

	common.NewAPIResponse("Registration successful", resp).WriteResponse(w, http.StatusOK)
}

func (d *Device) DeleteHandler(w http.ResponseWriter, r *http.Request) {
	sessionUser := models.GetUserFromContext(r)
	formUser := sessionUser
	username, ok := mux.Vars(r)["username"]
	if !ok {
		common.NewAPIResponse("No username given", nil).WriteResponse(w, http.StatusBadRequest)
		return
	}
	if username != sessionUser.Username {
		if !sessionUser.Can(models.DeleteDevice) {
			common.NewAPIResponse("Admin Error", nil).WriteResponse(w, http.StatusForbidden)
			return
		}
		var err error
		formUser, err = models.GetUserByUsername(d.e, username)
		if err != nil {
			d.e.Log.Errorf("Error getting user: %s", err.Error())
			common.NewAPIResponse("Server error", nil).WriteResponse(w, http.StatusInternalServerError)
			return
		}
	}

	if !sessionUser.Can(models.DeleteOwn) {
		common.NewAPIResponse("Permission denied", nil).WriteResponse(w, http.StatusForbidden)
		return
	}

	deleteAll := (r.FormValue("mac") == "")
	macsToDelete := strings.Split(r.FormValue("mac"), ",")
	usersDevices, err := models.GetDevicesForUser(d.e, formUser)
	if err != nil {
		d.e.Log.Errorf("Error deleting devices: %s", err.Error())
		common.NewAPIResponse("Error deleting devices", nil).WriteResponse(w, http.StatusInternalServerError)
		return
	}

	finishedWithErrors := false
	for _, device := range usersDevices {
		if !deleteAll && !common.StringInSlice(device.MAC.String(), macsToDelete) {
			continue
		}

		if err := device.Delete(); err != nil {
			d.e.Log.Errorf("Error deleting device %s: %s", device.MAC.String(), err.Error())
			finishedWithErrors = true
			continue
		}

		d.e.Log.Infof("Deleted device %s for user %s", device.MAC.String(), formUser.Username)
	}

	if finishedWithErrors {
		common.NewAPIResponse("Finished but with errors", nil).WriteResponse(w, http.StatusOK)
		return
	}

	common.NewAPIResponse("Devices deleted successful", nil).WriteResponse(w, http.StatusNoContent)
}

func (d *Device) ReassignHandler(w http.ResponseWriter, r *http.Request) {
	sessionUser := models.GetUserFromContext(r)
	if !sessionUser.Can(models.ReassignDevice) {
		common.NewEmptyAPIResponse().WriteResponse(w, http.StatusForbidden)
		return
	}

	username := r.FormValue("username")
	if username == "" {
		common.NewAPIResponse("Username required", nil).WriteResponse(w, http.StatusBadRequest)
		return
	}

	devices := r.FormValue("macs")
	if devices == "" {
		common.NewAPIResponse("At least one MAC address is required", nil).WriteResponse(w, http.StatusBadRequest)
		return
	}

	user, err := models.GetUserByUsername(d.e, username)
	if err != nil {
		d.e.Log.Errorf("Error getting user: %s", err.Error())
		common.NewAPIResponse("Server error", nil).WriteResponse(w, http.StatusInternalServerError)
		return
	}

	devicesToReassign := strings.Split(devices, ",")
	for _, devMacStr := range devicesToReassign {
		devMacStr = strings.TrimSpace(devMacStr)
		mac, err := common.FormatMacAddress(devMacStr)
		if err != nil {
			common.NewAPIResponse("Malformed MAC address "+devMacStr, nil).WriteResponse(w, http.StatusBadRequest)
			return
		}
		dev, err := models.GetDeviceByMAC(d.e, mac)
		if err != nil {
			d.e.Log.Errorf("Error getting device: %s", err.Error())
			common.NewAPIResponse("Server error", nil).WriteResponse(w, http.StatusInternalServerError)
			return
		}
		if dev.ID == 0 { // Device doesn't exist
			continue
		}
		originalUser := dev.Username
		dev.Username = user.Username
		// Change expiration to reflect new owner
		dev.Expires = user.DeviceExpiration.NextExpiration(d.e, time.Now())
		if err := dev.Save(); err != nil {
			d.e.Log.Errorf("Error saving device: %s", err.Error())
			common.NewAPIResponse("Error saving device", nil).WriteResponse(w, http.StatusInternalServerError)
			return
		}
		d.e.Log.WithFields(verbose.Fields{
			"adminUser":    sessionUser.Username,
			"assignedTo":   username,
			"assignedFrom": originalUser,
			"MAC":          mac.String(),
		}).Info("Reassigned device to another user")
	}

	common.NewAPIResponse("Devices reassigned successfully", nil).WriteResponse(w, http.StatusOK)
}
<commit_msg>Show what user deleted devices<commit_after>// This source file is part of the Packet Guardian project.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package api

import (
	"net"
	"net/http"
	"strings"
	"time"

	"github.com/gorilla/mux"
	"github.com/lfkeitel/verbose"
	"github.com/usi-lfkeitel/packet-guardian/src/common"
	"github.com/usi-lfkeitel/packet-guardian/src/models"
)

type Device struct {
	e *common.Environment
}

func NewDeviceController(e *common.Environment) *Device {
	return &Device{e: e}
}

func (d *Device) RegistrationHandler(w http.ResponseWriter, r *http.Request) {
	// Check authentication and get User models
	var formUser *models.User // The user to whom the device is being registered
	var err error
	sessionUser := models.GetUserFromContext(r)
	formUsername := strings.ToLower(r.FormValue("username"))
	if formUsername == "" {
		common.NewAPIResponse("No username given", nil).WriteResponse(w, http.StatusBadRequest)
		return
	}

	if sessionUser.Username != formUsername && !sessionUser.Can(models.CreateDevice) {
		d.e.Log.Errorf("Admin action attempted: Register device for %s attempted by user %s", formUsername, sessionUser.Username)
		common.NewAPIResponse("Permission denied", nil).WriteResponse(w, http.StatusForbidden)
		return
	}

	if formUsername == sessionUser.Username {
		if !sessionUser.Can(models.CreateOwn) {
			common.NewAPIResponse("Cannot register device - Permission denied", nil).WriteResponse(w, http.StatusForbidden)
			return
		}
		formUser = sessionUser
	} else {
		var err error
		formUser, err = models.GetUserByUsername(d.e, formUsername)
		if err != nil {
			d.e.Log.Errorf("Failed to get user from database %s: %s", formUsername, err.Error())
			common.NewAPIResponse("Error registering device", nil).WriteResponse(w, http.StatusInternalServerError)
			return
		}
	}

	if !sessionUser.Can(models.CreateDevice) {
		if formUser.IsBlacklisted() {
			d.e.Log.Noticef("Attempted registration by blacklisted user %s", formUser.Username)
			common.NewAPIResponse("Username blacklisted", nil).WriteResponse(w, http.StatusForbidden)
			return
		}

		// Get and enforce the device limit
		limit := models.UserDeviceLimit(d.e.Config.Registration.DefaultDeviceLimit)
		if formUser.DeviceLimit != models.UserDeviceLimitGlobal {
			limit = formUser.DeviceLimit
		}

		deviceCount, err := models.GetDeviceCountForUser(d.e, formUser)
		if err != nil {
			d.e.Log.Errorf("Error getting device count: %s", err.Error())
		}
		if limit != models.UserDeviceLimitUnlimited && deviceCount >= int(limit) {
			common.NewAPIResponse("Device limit reached", nil).WriteResponse(w, http.StatusConflict)
			return
		}
	}

	// Get MAC address
	var mac net.HardwareAddr
	macPost := r.FormValue("mac-address")
	manual := (macPost != "")
	ip := net.ParseIP(strings.Split(r.RemoteAddr, ":")[0])
	if manual {
		// Manual registration
		if !d.e.Config.Registration.AllowManualRegistrations {
			d.e.Log.Noticef("Unauthorized manual registration attempt for MAC %s from user %s", macPost, formUser.Username)
			common.NewAPIResponse("Manual registrations not allowed", nil).WriteResponse(w, http.StatusForbidden)
			return
		}
		mac, err = common.FormatMacAddress(macPost)
		if err != nil {
			common.NewAPIResponse("Incorrect MAC address format", nil).WriteResponse(w, http.StatusBadRequest)
			return
		}
	} else {
		// Automatic registration
		lease, err := models.GetLeaseByIP(d.e, ip)
		if err != nil {
			d.e.Log.Errorf("Failed to get MAC for IP %s: %s", ip, err.Error())
			common.NewAPIResponse("Failed detecting MAC address", nil).WriteResponse(w, http.StatusInternalServerError)
			return
		} else if lease.ID == 0 {
			d.e.Log.Errorf("Attempted automatic registration on non-leased device %s", ip)
			common.NewAPIResponse("Error detecting MAC address", nil).WriteResponse(w, http.StatusBadRequest)
			return
		}
		mac = lease.MAC
	}

	// Get device from database
	device, err := models.GetDeviceByMAC(d.e, mac)
	if err != nil {
		d.e.Log.Errorf("Error getting device: %s", err.Error())
		common.NewAPIResponse("Failed loading device", nil).WriteResponse(w, http.StatusInternalServerError)
		return
	}

	// Check if device is already registered
	if device.ID != 0 {
		d.e.Log.Noticef("Attempted duplicate registration of MAC %s to user %s", mac.String(), formUser.Username)
		common.NewAPIResponse("Device already registered", nil).WriteResponse(w, http.StatusConflict)
		return
	}

	// Validate platform, we don't want someone to submit an inappropiate value
	platform := ""
	if manual {
		if common.StringInSlice(r.FormValue("platform"), d.e.Config.Registration.ManualRegPlatforms) {
			platform = r.FormValue("platform")
		}
	} else {
		platform = common.ParseUserAgent(r.UserAgent())
	}

	// Fill in device information
	device.Username = formUser.Username
	device.Description = r.FormValue("description")
	device.RegisteredFrom = ip
	device.Platform = platform
	device.Expires = formUser.DeviceExpiration.NextExpiration(d.e, time.Now())
	device.DateRegistered = time.Now()
	device.LastSeen = time.Now()
	device.UserAgent = r.UserAgent()
	if manual {
		device.UserAgent = "Manual"
	}

	// Save new device
	if err := device.Save(); err != nil {
		d.e.Log.Errorf("Error registering device: %s", err.Error())
		common.NewAPIResponse("Error saving device", nil).WriteResponse(w, http.StatusInternalServerError)
		return
	}
	d.e.Log.Infof("Successfully registered MAC %s to user %s", mac.String(), formUser.Username)

	// Redirect client as needed
	resp := struct{ Location string }{Location: "/manage"}
	if sessionUser.Can(models.ViewDevices) {
		resp.Location = "/admin/manage/" + formUser.Username
	}

	common.NewAPIResponse("Registration successful", resp).WriteResponse(w, http.StatusOK)
}

func (d *Device) DeleteHandler(w http.ResponseWriter, r *http.Request) {
	sessionUser := models.GetUserFromContext(r)
	formUser := sessionUser
	username, ok := mux.Vars(r)["username"]
	if !ok {
		common.NewAPIResponse("No username given", nil).WriteResponse(w, http.StatusBadRequest)
		return
	}
	if username != sessionUser.Username {
		if !sessionUser.Can(models.DeleteDevice) {
			common.NewAPIResponse("Admin Error", nil).WriteResponse(w, http.StatusForbidden)
			return
		}
		var err error
		formUser, err = models.GetUserByUsername(d.e, username)
		if err != nil {
			d.e.Log.Errorf("Error getting user: %s", err.Error())
			common.NewAPIResponse("Server error", nil).WriteResponse(w, http.StatusInternalServerError)
			return
		}
	}

	if !sessionUser.Can(models.DeleteOwn) {
		common.NewAPIResponse("Permission denied", nil).WriteResponse(w, http.StatusForbidden)
		return
	}

	deleteAll := (r.FormValue("mac") == "")
	macsToDelete := strings.Split(r.FormValue("mac"), ",")
	usersDevices, err := models.GetDevicesForUser(d.e, formUser)
	if err != nil {
		d.e.Log.Errorf("Error deleting devices: %s", err.Error())
		common.NewAPIResponse("Error deleting devices", nil).WriteResponse(w, http.StatusInternalServerError)
		return
	}

	finishedWithErrors := false
	for _, device := range usersDevices {
		if !deleteAll && !common.StringInSlice(device.MAC.String(), macsToDelete) {
			continue
		}

		if err := device.Delete(); err != nil {
			d.e.Log.Errorf("Error deleting device %s: %s", device.MAC.String(), err.Error())
			finishedWithErrors = true
			continue
		}

		d.e.Log.Infof("Deleted device %s for user %s by %s", device.MAC.String(), formUser.Username, sessionUser.Username)
	}

	if finishedWithErrors {
		common.NewAPIResponse("Finished but with errors", nil).WriteResponse(w, http.StatusOK)
		return
	}

	common.NewAPIResponse("Devices deleted successful", nil).WriteResponse(w, http.StatusNoContent)
}

func (d *Device) ReassignHandler(w http.ResponseWriter, r *http.Request) {
	sessionUser := models.GetUserFromContext(r)
	if !sessionUser.Can(models.ReassignDevice) {
		common.NewEmptyAPIResponse().WriteResponse(w, http.StatusForbidden)
		return
	}

	username := r.FormValue("username")
	if username == "" {
		common.NewAPIResponse("Username required", nil).WriteResponse(w, http.StatusBadRequest)
		return
	}

	devices := r.FormValue("macs")
	if devices == "" {
		common.NewAPIResponse("At least one MAC address is required", nil).WriteResponse(w, http.StatusBadRequest)
		return
	}

	user, err := models.GetUserByUsername(d.e, username)
	if err != nil {
		d.e.Log.Errorf("Error getting user: %s", err.Error())
		common.NewAPIResponse("Server error", nil).WriteResponse(w, http.StatusInternalServerError)
		return
	}

	devicesToReassign := strings.Split(devices, ",")
	for _, devMacStr := range devicesToReassign {
		devMacStr = strings.TrimSpace(devMacStr)
		mac, err := common.FormatMacAddress(devMacStr)
		if err != nil {
			common.NewAPIResponse("Malformed MAC address "+devMacStr, nil).WriteResponse(w, http.StatusBadRequest)
			return
		}
		dev, err := models.GetDeviceByMAC(d.e, mac)
		if err != nil {
			d.e.Log.Errorf("Error getting device: %s", err.Error())
			common.NewAPIResponse("Server error", nil).WriteResponse(w, http.StatusInternalServerError)
			return
		}
		if dev.ID == 0 { // Device doesn't exist
			continue
		}
		originalUser := dev.Username
		dev.Username = user.Username
		// Change expiration to reflect new owner
		dev.Expires = user.DeviceExpiration.NextExpiration(d.e, time.Now())
		if err := dev.Save(); err != nil {
			d.e.Log.Errorf("Error saving device: %s", err.Error())
			common.NewAPIResponse("Error saving device", nil).WriteResponse(w, http.StatusInternalServerError)
			return
		}
		d.e.Log.WithFields(verbose.Fields{
			"adminUser":    sessionUser.Username,
			"assignedTo":   username,
			"assignedFrom": originalUser,
			"MAC":          mac.String(),
		}).Info("Reassigned device to another user")
	}

	common.NewAPIResponse("Devices reassigned successfully", nil).WriteResponse(w, http.StatusOK)
}
<|endoftext|>


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

package runtime_test

import (
	"bytes"
	"encoding/binary"
	"errors"
	"internal/testenv"
	"os/exec"
	"reflect"
	"runtime"
	"testing"
)

func TestFakeTime(t *testing.T) {
	if runtime.GOOS == "windows" {
		t.Skip("faketime not supported on windows")
	}

	t.Parallel()

	exe, err := buildTestProg(t, "testfaketime", "-tags=faketime")
	if err != nil {
		t.Fatal(err)
	}

	var stdout, stderr bytes.Buffer
	cmd := exec.Command(exe)
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr

	err = testenv.CleanCmdEnv(cmd).Run()
	if err != nil {
		t.Fatalf("exit status: %v\n%s", err, stderr.String())
	}

	t.Logf("raw stdout: %q", stdout.String())
	t.Logf("raw stderr: %q", stdout.String())

	f1, err1 := parseFakeTime(stdout.Bytes())
	if err1 != nil {
		t.Fatal(err1)
	}
	f2, err2 := parseFakeTime(stderr.Bytes())
	if err2 != nil {
		t.Fatal(err2)
	}

	const time0 = 1257894000000000000
	got := [][]fakeTimeFrame{f1, f2}
	var want = [][]fakeTimeFrame{{
		{time0 + 1, "line 2\n"},
		{time0 + 1, "line 3\n"},
		{time0 + 1e9, "line 5\n"},
		{time0 + 1e9, "2009-11-10T23:00:01Z"},
	}, {
		{time0, "line 1\n"},
		{time0 + 2, "line 4\n"},
	}}
	if !reflect.DeepEqual(want, got) {
		t.Fatalf("want %v, got %v", want, got)
	}
}

type fakeTimeFrame struct {
	time uint64
	data string
}

func parseFakeTime(x []byte) ([]fakeTimeFrame, error) {
	var frames []fakeTimeFrame
	for len(x) != 0 {
		if len(x) < 4+8+4 {
			return nil, errors.New("truncated header")
		}
		const magic = "\x00\x00PB"
		if string(x[:len(magic)]) != magic {
			return nil, errors.New("bad magic")
		}
		x = x[len(magic):]
		time := binary.BigEndian.Uint64(x)
		x = x[8:]
		dlen := binary.BigEndian.Uint32(x)
		x = x[4:]
		data := string(x[:dlen])
		x = x[dlen:]
		frames = append(frames, fakeTimeFrame{time, data})
	}
	return frames, nil
}
<commit_msg>runtime: correctly log stderr in TestFakeTime<commit_after>// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package runtime_test

import (
	"bytes"
	"encoding/binary"
	"errors"
	"internal/testenv"
	"os/exec"
	"reflect"
	"runtime"
	"testing"
)

func TestFakeTime(t *testing.T) {
	if runtime.GOOS == "windows" {
		t.Skip("faketime not supported on windows")
	}

	t.Parallel()

	exe, err := buildTestProg(t, "testfaketime", "-tags=faketime")
	if err != nil {
		t.Fatal(err)
	}

	var stdout, stderr bytes.Buffer
	cmd := exec.Command(exe)
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr

	err = testenv.CleanCmdEnv(cmd).Run()
	if err != nil {
		t.Fatalf("exit status: %v\n%s", err, stderr.String())
	}

	t.Logf("raw stdout: %q", stdout.String())
	t.Logf("raw stderr: %q", stderr.String())

	f1, err1 := parseFakeTime(stdout.Bytes())
	if err1 != nil {
		t.Fatal(err1)
	}
	f2, err2 := parseFakeTime(stderr.Bytes())
	if err2 != nil {
		t.Fatal(err2)
	}

	const time0 = 1257894000000000000
	got := [][]fakeTimeFrame{f1, f2}
	var want = [][]fakeTimeFrame{{
		{time0 + 1, "line 2\n"},
		{time0 + 1, "line 3\n"},
		{time0 + 1e9, "line 5\n"},
		{time0 + 1e9, "2009-11-10T23:00:01Z"},
	}, {
		{time0, "line 1\n"},
		{time0 + 2, "line 4\n"},
	}}
	if !reflect.DeepEqual(want, got) {
		t.Fatalf("want %v, got %v", want, got)
	}
}

type fakeTimeFrame struct {
	time uint64
	data string
}

func parseFakeTime(x []byte) ([]fakeTimeFrame, error) {
	var frames []fakeTimeFrame
	for len(x) != 0 {
		if len(x) < 4+8+4 {
			return nil, errors.New("truncated header")
		}
		const magic = "\x00\x00PB"
		if string(x[:len(magic)]) != magic {
			return nil, errors.New("bad magic")
		}
		x = x[len(magic):]
		time := binary.BigEndian.Uint64(x)
		x = x[8:]
		dlen := binary.BigEndian.Uint32(x)
		x = x[4:]
		data := string(x[:dlen])
		x = x[dlen:]
		frames = append(frames, fakeTimeFrame{time, data})
	}
	return frames, nil
}
<|endoftext|>