<commit_before>/*
Copyright 2019 The Jetstack cert-manager contributors.

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 cainjector

import (
	"context"
	"fmt"
	"io/ioutil"

	logf "github.com/jetstack/cert-manager/pkg/logs"
	"github.com/pkg/errors"
	"golang.org/x/sync/errgroup"

	admissionreg "k8s.io/api/admissionregistration/v1beta1"
	apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
	"k8s.io/apimachinery/pkg/api/meta"
	"k8s.io/apimachinery/pkg/runtime"
	apireg "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1beta1"
	ctrl "sigs.k8s.io/controller-runtime"
	"sigs.k8s.io/controller-runtime/pkg/cache"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/controller"
	"sigs.k8s.io/controller-runtime/pkg/handler"
	"sigs.k8s.io/controller-runtime/pkg/manager"
	"sigs.k8s.io/controller-runtime/pkg/source"
)

// injectorSet describes a particular setup of the injector controller
type injectorSetup struct {
	resourceName string
	injector     CertInjector
	listType     runtime.Object
}

var (
	MutatingWebhookSetup = injectorSetup{
		resourceName: "mutatingwebhookconfiguration",
		injector:     mutatingWebhookInjector{},
		listType:     &admissionreg.MutatingWebhookConfigurationList{},
	}

	ValidatingWebhookSetup = injectorSetup{
		resourceName: "validatingwebhookconfiguration",
		injector:     validatingWebhookInjector{},
		listType:     &admissionreg.ValidatingWebhookConfigurationList{},
	}

	APIServiceSetup = injectorSetup{
		resourceName: "apiservice",
		injector:     apiServiceInjector{},
		listType:     &apireg.APIServiceList{},
	}

	CRDSetup = injectorSetup{
		resourceName: "customresourcedefinition",
		injector:     crdConversionInjector{},
		listType:     &apiext.CustomResourceDefinitionList{},
	}

	injectorSetups  = []injectorSetup{MutatingWebhookSetup, ValidatingWebhookSetup, APIServiceSetup, CRDSetup}
	ControllerNames []string
)

// registerAllInjectors registers all injectors and based on the
// graduation state of the injector decides how to log no kind/resource match errors
func registerAllInjectors(ctx context.Context, groupName string, mgr ctrl.Manager, sources []caDataSource, client client.Client, ca cache.Cache) error {
	controllers := make([]controller.Controller, len(injectorSetups))
	for i, setup := range injectorSetups {
		controller, err := Register(groupName, mgr, setup, sources, ca, client)
		if err != nil {
			if !meta.IsNoMatchError(err) || !setup.injector.IsAlpha() {
				return err
			}
			ctrl.Log.V(logf.WarnLevel).Info("unable to register injector which is still in an alpha phase."+
				" Enable the feature on the API server in order to use this injector",
				"injector", setup.resourceName)
		}
		controllers[i] = controller
	}
	g, gctx := errgroup.WithContext(ctx)

	g.Go(func() (err error) {
		if err = ca.Start(gctx.Done()); err != nil {
			return errors.WithStack(err)
		}
		return nil
	})
	if ca.WaitForCacheSync(gctx.Done()) {
		for _, controller := range controllers {
			if gctx.Err() != nil {
				continue
			}
			controller := controller
			g.Go(func() (err error) {
				return controller.Start(gctx.Done())
			})
		}
	}
	return g.Wait()
}

// Register registers an injection controller with the given manager, and adds relevant indicies.
func Register(groupName string, mgr ctrl.Manager, setup injectorSetup, sources []caDataSource, ca cache.Cache, client client.Client) (controller.Controller, error) {
	log := ctrl.Log.WithName(groupName).WithName(setup.resourceName)
	typ := setup.injector.NewTarget().AsObject()

	c, err := controller.NewUnmanaged(
		// XXX:  strings.ToLower(typ.GetObjectKind().GroupVersionKind().Kind),
		fmt.Sprintf("controller-for-%s-%s", groupName, setup.resourceName),
		mgr,
		controller.Options{
			Reconciler: &genericInjectReconciler{
				Client:       client,
				sources:      sources,
				log:          log.WithName("generic-inject-reconciler"),
				resourceName: setup.resourceName,
				injector:     setup.injector,
			},
			Log:                     log,
			MaxConcurrentReconciles: 5,
		})
	if err != nil {
		return nil, errors.WithStack(err)
	}
	if err := c.Watch(source.NewKindWithCache(typ, ca), &handler.EnqueueRequestForObject{}); err != nil {
		return nil, errors.WithStack(err)
	}

	for _, s := range sources {
		if err := s.ApplyTo(mgr, setup, c, ca); err != nil {
			return nil, err
		}
	}

	return c, nil
}

// dataFromSliceOrFile returns data from the slice (if non-empty), or from the file,
// or an error if an error occurred reading the file
func dataFromSliceOrFile(data []byte, file string) ([]byte, error) {
	if len(data) > 0 {
		return data, nil
	}
	if len(file) > 0 {
		fileData, err := ioutil.ReadFile(file)
		if err != nil {
			return []byte{}, err
		}
		return fileData, nil
	}
	return nil, nil
}

// RegisterCertificateBased registers all known injection controllers that
// target Certificate resources with the  given manager, and adds relevant
// indices.
// The registered controllers require the cert-manager API to be available
// in order to run.
func RegisterCertificateBased(ctx context.Context, mgr ctrl.Manager) error {
	cache, client, err := newIndependentCacheAndDelegatingClient(mgr)
	if err != nil {
		return err
	}
	return registerAllInjectors(
		ctx,
		"certificate",
		mgr,
		[]caDataSource{
			&certificateDataSource{client: cache},
		},
		client,
		cache,
	)
}

// RegisterSecretBased registers all known injection controllers that
// target Secret resources with the  given manager, and adds relevant
// indices.
// The registered controllers only require the corev1 APi to be available in
// order to run.
func RegisterSecretBased(ctx context.Context, mgr ctrl.Manager) error {
	cache, client, err := newIndependentCacheAndDelegatingClient(mgr)
	if err != nil {
		return err
	}
	return registerAllInjectors(
		ctx,
		"secret",
		mgr,
		[]caDataSource{
			&secretDataSource{client: cache},
			&kubeconfigDataSource{},
		},
		client,
		cache,
	)
}

func newIndependentCacheAndDelegatingClient(mgr ctrl.Manager) (cache.Cache, client.Client, error) {
	cacheOptions := cache.Options{
		Scheme: mgr.GetScheme(),
		Mapper: mgr.GetRESTMapper(),
	}
	ca, err := cache.New(mgr.GetConfig(), cacheOptions)
	if err != nil {
		return nil, nil, errors.WithStack(err)
	}

	clientOptions := client.Options{
		Scheme: mgr.GetScheme(),
		Mapper: mgr.GetRESTMapper(),
	}
	client, err := manager.DefaultNewClient(ca, mgr.GetConfig(), clientOptions)
	if err != nil {
		return nil, nil, errors.WithStack(err)
	}
	return ca, client, nil
}
<commit_msg>A clearer name for the function which creates each controller<commit_after>/*
Copyright 2019 The Jetstack cert-manager contributors.

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 cainjector

import (
	"context"
	"fmt"
	"io/ioutil"

	logf "github.com/jetstack/cert-manager/pkg/logs"
	"github.com/pkg/errors"
	"golang.org/x/sync/errgroup"

	admissionreg "k8s.io/api/admissionregistration/v1beta1"
	apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
	"k8s.io/apimachinery/pkg/api/meta"
	"k8s.io/apimachinery/pkg/runtime"
	apireg "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1beta1"
	ctrl "sigs.k8s.io/controller-runtime"
	"sigs.k8s.io/controller-runtime/pkg/cache"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/controller"
	"sigs.k8s.io/controller-runtime/pkg/handler"
	"sigs.k8s.io/controller-runtime/pkg/manager"
	"sigs.k8s.io/controller-runtime/pkg/source"
)

// injectorSet describes a particular setup of the injector controller
type injectorSetup struct {
	resourceName string
	injector     CertInjector
	listType     runtime.Object
}

var (
	MutatingWebhookSetup = injectorSetup{
		resourceName: "mutatingwebhookconfiguration",
		injector:     mutatingWebhookInjector{},
		listType:     &admissionreg.MutatingWebhookConfigurationList{},
	}

	ValidatingWebhookSetup = injectorSetup{
		resourceName: "validatingwebhookconfiguration",
		injector:     validatingWebhookInjector{},
		listType:     &admissionreg.ValidatingWebhookConfigurationList{},
	}

	APIServiceSetup = injectorSetup{
		resourceName: "apiservice",
		injector:     apiServiceInjector{},
		listType:     &apireg.APIServiceList{},
	}

	CRDSetup = injectorSetup{
		resourceName: "customresourcedefinition",
		injector:     crdConversionInjector{},
		listType:     &apiext.CustomResourceDefinitionList{},
	}

	injectorSetups  = []injectorSetup{MutatingWebhookSetup, ValidatingWebhookSetup, APIServiceSetup, CRDSetup}
	ControllerNames []string
)

// registerAllInjectors registers all injectors and based on the
// graduation state of the injector decides how to log no kind/resource match errors
func registerAllInjectors(ctx context.Context, groupName string, mgr ctrl.Manager, sources []caDataSource, client client.Client, ca cache.Cache) error {
	controllers := make([]controller.Controller, len(injectorSetups))
	for i, setup := range injectorSetups {
		controller, err := newGenericInjectionController(groupName, mgr, setup, sources, ca, client)
		if err != nil {
			if !meta.IsNoMatchError(err) || !setup.injector.IsAlpha() {
				return err
			}
			ctrl.Log.V(logf.WarnLevel).Info("unable to register injector which is still in an alpha phase."+
				" Enable the feature on the API server in order to use this injector",
				"injector", setup.resourceName)
		}
		controllers[i] = controller
	}
	g, gctx := errgroup.WithContext(ctx)

	g.Go(func() (err error) {
		if err = ca.Start(gctx.Done()); err != nil {
			return errors.WithStack(err)
		}
		return nil
	})
	if ca.WaitForCacheSync(gctx.Done()) {
		for _, controller := range controllers {
			if gctx.Err() != nil {
				continue
			}
			controller := controller
			g.Go(func() (err error) {
				return controller.Start(gctx.Done())
			})
		}
	}
	return g.Wait()
}

// newGenericInjectionController creates a controller and adds relevant watches
// and indexers to the supplied cache.
func newGenericInjectionController(groupName string, mgr ctrl.Manager, setup injectorSetup, sources []caDataSource, ca cache.Cache, client client.Client) (controller.Controller, error) {
	log := ctrl.Log.WithName(groupName).WithName(setup.resourceName)
	typ := setup.injector.NewTarget().AsObject()

	c, err := controller.NewUnmanaged(
		fmt.Sprintf("controller-for-%s-%s", groupName, setup.resourceName),
		mgr,
		controller.Options{
			Reconciler: &genericInjectReconciler{
				Client:       client,
				sources:      sources,
				log:          log.WithName("generic-inject-reconciler"),
				resourceName: setup.resourceName,
				injector:     setup.injector,
			},
			Log:                     log,
			MaxConcurrentReconciles: 5,
		})
	if err != nil {
		return nil, errors.WithStack(err)
	}
	if err := c.Watch(source.NewKindWithCache(typ, ca), &handler.EnqueueRequestForObject{}); err != nil {
		return nil, errors.WithStack(err)
	}

	for _, s := range sources {
		if err := s.ApplyTo(mgr, setup, c, ca); err != nil {
			return nil, err
		}
	}

	return c, nil
}

// dataFromSliceOrFile returns data from the slice (if non-empty), or from the file,
// or an error if an error occurred reading the file
func dataFromSliceOrFile(data []byte, file string) ([]byte, error) {
	if len(data) > 0 {
		return data, nil
	}
	if len(file) > 0 {
		fileData, err := ioutil.ReadFile(file)
		if err != nil {
			return []byte{}, err
		}
		return fileData, nil
	}
	return nil, nil
}

// RegisterCertificateBased registers all known injection controllers that
// target Certificate resources with the  given manager, and adds relevant
// indices.
// The registered controllers require the cert-manager API to be available
// in order to run.
func RegisterCertificateBased(ctx context.Context, mgr ctrl.Manager) error {
	cache, client, err := newIndependentCacheAndDelegatingClient(mgr)
	if err != nil {
		return err
	}
	return registerAllInjectors(
		ctx,
		"certificate",
		mgr,
		[]caDataSource{
			&certificateDataSource{client: cache},
		},
		client,
		cache,
	)
}

// RegisterSecretBased registers all known injection controllers that
// target Secret resources with the  given manager, and adds relevant
// indices.
// The registered controllers only require the corev1 APi to be available in
// order to run.
func RegisterSecretBased(ctx context.Context, mgr ctrl.Manager) error {
	cache, client, err := newIndependentCacheAndDelegatingClient(mgr)
	if err != nil {
		return err
	}
	return registerAllInjectors(
		ctx,
		"secret",
		mgr,
		[]caDataSource{
			&secretDataSource{client: cache},
			&kubeconfigDataSource{},
		},
		client,
		cache,
	)
}

func newIndependentCacheAndDelegatingClient(mgr ctrl.Manager) (cache.Cache, client.Client, error) {
	cacheOptions := cache.Options{
		Scheme: mgr.GetScheme(),
		Mapper: mgr.GetRESTMapper(),
	}
	ca, err := cache.New(mgr.GetConfig(), cacheOptions)
	if err != nil {
		return nil, nil, errors.WithStack(err)
	}

	clientOptions := client.Options{
		Scheme: mgr.GetScheme(),
		Mapper: mgr.GetRESTMapper(),
	}
	client, err := manager.DefaultNewClient(ca, mgr.GetConfig(), clientOptions)
	if err != nil {
		return nil, nil, errors.WithStack(err)
	}
	return ca, client, nil
}
<|endoftext|>


<commit_before>// Copyright 2016-2019 Authors of Cilium
//
// 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 linux

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/cilium/cilium/pkg/bpf"
	"github.com/cilium/cilium/pkg/defaults"
	"github.com/cilium/cilium/pkg/logging/logfields"
	"github.com/cilium/cilium/pkg/option"
	"github.com/cilium/cilium/pkg/versioncheck"

	go_version "github.com/blang/semver"
	"golang.org/x/sys/unix"
)

const (
	minKernelVer = "4.8.0"
	minClangVer  = "3.8.0"
	recKernelVer = "4.9.0"
	recClangVer  = "3.9.0"
)

var (
	isMinKernelVer = versioncheck.MustCompile(">=" + minKernelVer)
	isMinClangVer  = versioncheck.MustCompile(">=" + minClangVer)

	isRecKernelVer = versioncheck.MustCompile(">=" + recKernelVer)
	isRecClangVer  = versioncheck.MustCompile(">=" + recClangVer)

	// LLVM/clang version which supports `-mattr=dwarfris`
	isDwarfrisClangVer         = versioncheck.MustCompile(">=7.0.0")
	canDisableDwarfRelocations bool
)

func parseKernelVersion(ver string) (go_version.Version, error) {
	verStrs := strings.Split(ver, ".")
	switch {
	case len(verStrs) < 2:
		return go_version.Version{}, fmt.Errorf("unable to get kernel version from %q", ver)
	case len(verStrs) < 3:
		verStrs = append(verStrs, "0")
	}
	// We are assuming the kernel version will be something as:
	// 4.9.17-040917-generic

	// If verStrs is []string{ "4", "9", "17-040917-generic" }
	// then we need to retrieve patch number.
	patch := regexp.MustCompilePOSIX(`^[0-9]+`).FindString(verStrs[2])
	if patch == "" {
		verStrs[2] = "0"
	} else {
		verStrs[2] = patch
	}
	return versioncheck.Version(strings.Join(verStrs[:3], "."))
}

// GetKernelVersion returns the version of the Linux kernel running on this host.
func GetKernelVersion() (go_version.Version, error) {
	var unameBuf unix.Utsname
	if err := unix.Uname(&unameBuf); err != nil {
		log.WithError(err).Fatal("kernel version: NOT OK")
	}
	return parseKernelVersion(string(unameBuf.Release[:]))
}

func getClangVersion(filePath string) (go_version.Version, error) {
	verOut, err := exec.Command(filePath, "--version").CombinedOutput()
	if err != nil {
		log.WithError(err).Fatal("clang version: NOT OK")
	}
	res := regexp.MustCompile(`(clang version )([^ ]*)`).FindStringSubmatch(string(verOut))
	if len(res) != 3 {
		log.Fatalf("clang version: NOT OK: unable to get clang's version "+
			"from: %q", string(verOut))
	}
	// at this point res is []string{"clang", "version", "maj.min.patch"}
	verStrs := strings.Split(res[2], ".")
	if len(verStrs) < 3 {
		return go_version.Version{}, fmt.Errorf("unable to get clang version from %q", string(verOut))
	}
	v := strings.Join(verStrs[:3], ".")
	// Handle Ubuntu versioning by removing the dash and everything after.
	// F. ex. `4.0.0-1ubuntu1~16 -> 4.0.0` and `3.8.0-2ubuntu4 -> 3.8.0`.
	v = strings.Split(v, "-")[0]
	return versioncheck.Version(v)
}

func checkBPFLogs(logType string, fatal bool) {
	bpfLogFile := logType + ".log"
	bpfLogPath := filepath.Join(option.Config.StateDir, bpfLogFile)

	if _, err := os.Stat(bpfLogPath); os.IsNotExist(err) {
		log.Infof("%s check: OK!", logType)
	} else if err == nil {
		bpfFeaturesLog, err := ioutil.ReadFile(bpfLogPath)
		if err != nil {
			log.WithError(err).WithField(logfields.Path, bpfLogPath).Fatalf("%s check: NOT OK. Unable to read", logType)
		}
		printer := log.Debugf
		if fatal {
			printer = log.Errorf
			printer("%s check: NOT OK", logType)
		} else {
			printer("%s check: Some features may be limited:", logType)
		}
		lines := strings.Trim(string(bpfFeaturesLog), "\n")
		for _, line := range strings.Split(lines, "\n") {
			printer(line)
		}
		if fatal {
			log.Fatalf("%s check failed.", logType)
		}
	} else {
		log.WithError(err).WithField(logfields.Path, bpfLogPath).Fatalf("%s check: NOT OK. Unable to read", logType)
	}
}

func CheckMinRequirements() {
	kernelVersion, err := GetKernelVersion()
	if err != nil {
		log.WithError(err).Fatal("kernel version: NOT OK")
	}
	if !isMinKernelVer(kernelVersion) {
		log.Fatalf("kernel version: NOT OK: minimal supported kernel "+
			"version is %s; kernel version that is running is: %s", minKernelVer, kernelVersion)
	}

	if option.Config.EnableIPv6 {
		if _, err := os.Stat("/proc/net/if_inet6"); os.IsNotExist(err) {
			log.Fatalf("kernel: ipv6 is enabled in agent but ipv6 is either disabled or not compiled in the kernel")
		}
	}

	if filePath, err := exec.LookPath("clang"); err != nil {
		log.WithError(err).Fatal("clang: NOT OK")
	} else {
		clangVersion, err := getClangVersion(filePath)
		if err != nil {
			log.WithError(err).Fatal("clang: NOT OK")
		}
		if !isMinClangVer(clangVersion) {
			log.Fatalf("clang version: NOT OK: minimal supported clang "+
				"version is %s; clang version that is running is: %s", minClangVer, clangVersion)
		}
		//clang >= 3.9 / kernel < 4.9 - does not work
		if isRecClangVer(clangVersion) && !isRecKernelVer(kernelVersion) {
			log.Fatalf("clang (%s) and kernel (%s) version: NOT OK: please upgrade "+
				"your kernel version to at least %s",
				clangVersion, kernelVersion, recKernelVer)
		}
		canDisableDwarfRelocations = isDwarfrisClangVer(clangVersion)
		log.Infof("clang (%s) and kernel (%s) versions: OK!", clangVersion, kernelVersion)
	}

	if filePath, err := exec.LookPath("llc"); err != nil {
		log.WithError(err).Fatal("llc: NOT OK")
	} else {
		lccVersion, err := exec.Command(filePath, "--version").CombinedOutput()
		if err == nil {
			if strings.Contains(strings.ToLower(string(lccVersion)), "debug") {
				log.Warn("llc version was compiled in debug mode, expect higher latency!")
			}
		}
		// /usr/include/gnu/stubs-32.h is installed by 'glibc-devel.i686' in fedora
		// /usr/include/sys/cdefs.h is installed by 'libc6-dev-i386' in ubuntu
		// both files exist on both systems but cdefs.h already exists in fedora
		// without 'glibc-devel.i686' so we check for 'stubs-32.h first.
		if _, err := os.Stat("/usr/include/gnu/stubs-32.h"); os.IsNotExist(err) {
			log.Fatal("linking environment: NOT OK, please make sure you have 'glibc-devel.i686' if you use fedora system or 'libc6-dev-i386' if you use ubuntu system")
		}
		if _, err := os.Stat("/usr/include/sys/cdefs.h"); os.IsNotExist(err) {
			log.Fatal("linking environment: NOT OK, please make sure you have 'libc6-dev-i386' in your ubuntu system")
		}
		log.Info("linking environment: OK!")
	}

	globalsDir := option.Config.GetGlobalsDir()
	if err := os.MkdirAll(globalsDir, defaults.StateDirRights); err != nil {
		log.WithError(err).WithField(logfields.Path, globalsDir).Fatal("Could not create runtime directory")
	}
	if err := os.Chdir(option.Config.LibDir); err != nil {
		log.WithError(err).WithField(logfields.Path, option.Config.LibDir).Fatal("Could not change to runtime directory")
	}
	probeScript := filepath.Join(option.Config.BpfDir, "run_probes.sh")
	if err := exec.Command(probeScript, option.Config.BpfDir, option.Config.StateDir).Run(); err != nil {
		log.WithError(err).Fatal("BPF Verifier: NOT OK. Unable to run checker for bpf_features")
	}
	featuresFilePath := filepath.Join(globalsDir, "bpf_features.h")
	if _, err := os.Stat(featuresFilePath); os.IsNotExist(err) {
		log.WithError(err).WithField(logfields.Path, globalsDir).Fatal("BPF Verifier: NOT OK. Unable to read bpf_features.h")
	}

	checkBPFLogs("bpf_requirements", true)
	checkBPFLogs("bpf_features", false)
	bpf.ReadFeatureProbes(featuresFilePath)
}
<commit_msg>linux: add doc for `CheckMinRequirements`<commit_after>// Copyright 2016-2019 Authors of Cilium
//
// 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 linux

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/cilium/cilium/pkg/bpf"
	"github.com/cilium/cilium/pkg/defaults"
	"github.com/cilium/cilium/pkg/logging/logfields"
	"github.com/cilium/cilium/pkg/option"
	"github.com/cilium/cilium/pkg/versioncheck"

	go_version "github.com/blang/semver"
	"golang.org/x/sys/unix"
)

const (
	minKernelVer = "4.8.0"
	minClangVer  = "3.8.0"
	recKernelVer = "4.9.0"
	recClangVer  = "3.9.0"
)

var (
	isMinKernelVer = versioncheck.MustCompile(">=" + minKernelVer)
	isMinClangVer  = versioncheck.MustCompile(">=" + minClangVer)

	isRecKernelVer = versioncheck.MustCompile(">=" + recKernelVer)
	isRecClangVer  = versioncheck.MustCompile(">=" + recClangVer)

	// LLVM/clang version which supports `-mattr=dwarfris`
	isDwarfrisClangVer         = versioncheck.MustCompile(">=7.0.0")
	canDisableDwarfRelocations bool
)

func parseKernelVersion(ver string) (go_version.Version, error) {
	verStrs := strings.Split(ver, ".")
	switch {
	case len(verStrs) < 2:
		return go_version.Version{}, fmt.Errorf("unable to get kernel version from %q", ver)
	case len(verStrs) < 3:
		verStrs = append(verStrs, "0")
	}
	// We are assuming the kernel version will be something as:
	// 4.9.17-040917-generic

	// If verStrs is []string{ "4", "9", "17-040917-generic" }
	// then we need to retrieve patch number.
	patch := regexp.MustCompilePOSIX(`^[0-9]+`).FindString(verStrs[2])
	if patch == "" {
		verStrs[2] = "0"
	} else {
		verStrs[2] = patch
	}
	return versioncheck.Version(strings.Join(verStrs[:3], "."))
}

// GetKernelVersion returns the version of the Linux kernel running on this host.
func GetKernelVersion() (go_version.Version, error) {
	var unameBuf unix.Utsname
	if err := unix.Uname(&unameBuf); err != nil {
		log.WithError(err).Fatal("kernel version: NOT OK")
	}
	return parseKernelVersion(string(unameBuf.Release[:]))
}

func getClangVersion(filePath string) (go_version.Version, error) {
	verOut, err := exec.Command(filePath, "--version").CombinedOutput()
	if err != nil {
		log.WithError(err).Fatal("clang version: NOT OK")
	}
	res := regexp.MustCompile(`(clang version )([^ ]*)`).FindStringSubmatch(string(verOut))
	if len(res) != 3 {
		log.Fatalf("clang version: NOT OK: unable to get clang's version "+
			"from: %q", string(verOut))
	}
	// at this point res is []string{"clang", "version", "maj.min.patch"}
	verStrs := strings.Split(res[2], ".")
	if len(verStrs) < 3 {
		return go_version.Version{}, fmt.Errorf("unable to get clang version from %q", string(verOut))
	}
	v := strings.Join(verStrs[:3], ".")
	// Handle Ubuntu versioning by removing the dash and everything after.
	// F. ex. `4.0.0-1ubuntu1~16 -> 4.0.0` and `3.8.0-2ubuntu4 -> 3.8.0`.
	v = strings.Split(v, "-")[0]
	return versioncheck.Version(v)
}

func checkBPFLogs(logType string, fatal bool) {
	bpfLogFile := logType + ".log"
	bpfLogPath := filepath.Join(option.Config.StateDir, bpfLogFile)

	if _, err := os.Stat(bpfLogPath); os.IsNotExist(err) {
		log.Infof("%s check: OK!", logType)
	} else if err == nil {
		bpfFeaturesLog, err := ioutil.ReadFile(bpfLogPath)
		if err != nil {
			log.WithError(err).WithField(logfields.Path, bpfLogPath).Fatalf("%s check: NOT OK. Unable to read", logType)
		}
		printer := log.Debugf
		if fatal {
			printer = log.Errorf
			printer("%s check: NOT OK", logType)
		} else {
			printer("%s check: Some features may be limited:", logType)
		}
		lines := strings.Trim(string(bpfFeaturesLog), "\n")
		for _, line := range strings.Split(lines, "\n") {
			printer(line)
		}
		if fatal {
			log.Fatalf("%s check failed.", logType)
		}
	} else {
		log.WithError(err).WithField(logfields.Path, bpfLogPath).Fatalf("%s check: NOT OK. Unable to read", logType)
	}
}

// CheckMinRequirements checks that minimum kernel requirements are met for
// configuring the BPF datapath. If not, fatally exits.
func CheckMinRequirements() {
	kernelVersion, err := GetKernelVersion()
	if err != nil {
		log.WithError(err).Fatal("kernel version: NOT OK")
	}
	if !isMinKernelVer(kernelVersion) {
		log.Fatalf("kernel version: NOT OK: minimal supported kernel "+
			"version is %s; kernel version that is running is: %s", minKernelVer, kernelVersion)
	}

	if option.Config.EnableIPv6 {
		if _, err := os.Stat("/proc/net/if_inet6"); os.IsNotExist(err) {
			log.Fatalf("kernel: ipv6 is enabled in agent but ipv6 is either disabled or not compiled in the kernel")
		}
	}

	if filePath, err := exec.LookPath("clang"); err != nil {
		log.WithError(err).Fatal("clang: NOT OK")
	} else {
		clangVersion, err := getClangVersion(filePath)
		if err != nil {
			log.WithError(err).Fatal("clang: NOT OK")
		}
		if !isMinClangVer(clangVersion) {
			log.Fatalf("clang version: NOT OK: minimal supported clang "+
				"version is %s; clang version that is running is: %s", minClangVer, clangVersion)
		}
		//clang >= 3.9 / kernel < 4.9 - does not work
		if isRecClangVer(clangVersion) && !isRecKernelVer(kernelVersion) {
			log.Fatalf("clang (%s) and kernel (%s) version: NOT OK: please upgrade "+
				"your kernel version to at least %s",
				clangVersion, kernelVersion, recKernelVer)
		}
		canDisableDwarfRelocations = isDwarfrisClangVer(clangVersion)
		log.Infof("clang (%s) and kernel (%s) versions: OK!", clangVersion, kernelVersion)
	}

	if filePath, err := exec.LookPath("llc"); err != nil {
		log.WithError(err).Fatal("llc: NOT OK")
	} else {
		lccVersion, err := exec.Command(filePath, "--version").CombinedOutput()
		if err == nil {
			if strings.Contains(strings.ToLower(string(lccVersion)), "debug") {
				log.Warn("llc version was compiled in debug mode, expect higher latency!")
			}
		}
		// /usr/include/gnu/stubs-32.h is installed by 'glibc-devel.i686' in fedora
		// /usr/include/sys/cdefs.h is installed by 'libc6-dev-i386' in ubuntu
		// both files exist on both systems but cdefs.h already exists in fedora
		// without 'glibc-devel.i686' so we check for 'stubs-32.h first.
		if _, err := os.Stat("/usr/include/gnu/stubs-32.h"); os.IsNotExist(err) {
			log.Fatal("linking environment: NOT OK, please make sure you have 'glibc-devel.i686' if you use fedora system or 'libc6-dev-i386' if you use ubuntu system")
		}
		if _, err := os.Stat("/usr/include/sys/cdefs.h"); os.IsNotExist(err) {
			log.Fatal("linking environment: NOT OK, please make sure you have 'libc6-dev-i386' in your ubuntu system")
		}
		log.Info("linking environment: OK!")
	}

	globalsDir := option.Config.GetGlobalsDir()
	if err := os.MkdirAll(globalsDir, defaults.StateDirRights); err != nil {
		log.WithError(err).WithField(logfields.Path, globalsDir).Fatal("Could not create runtime directory")
	}
	if err := os.Chdir(option.Config.LibDir); err != nil {
		log.WithError(err).WithField(logfields.Path, option.Config.LibDir).Fatal("Could not change to runtime directory")
	}
	probeScript := filepath.Join(option.Config.BpfDir, "run_probes.sh")
	if err := exec.Command(probeScript, option.Config.BpfDir, option.Config.StateDir).Run(); err != nil {
		log.WithError(err).Fatal("BPF Verifier: NOT OK. Unable to run checker for bpf_features")
	}
	featuresFilePath := filepath.Join(globalsDir, "bpf_features.h")
	if _, err := os.Stat(featuresFilePath); os.IsNotExist(err) {
		log.WithError(err).WithField(logfields.Path, globalsDir).Fatal("BPF Verifier: NOT OK. Unable to read bpf_features.h")
	}

	checkBPFLogs("bpf_requirements", true)
	checkBPFLogs("bpf_features", false)
	bpf.ReadFeatureProbes(featuresFilePath)
}
<|endoftext|>


<commit_before>package trades

import (
	"fmt"

	"github.com/bitfinexcom/bitfinex-api-go/pkg/convert"
)

type FundingTrade struct {
	Pair   string
	ID     int64
	MTS    int64
	Amount float64
	Rate   float64
	Period int
}

type FundingTradeUpdate FundingTrade
type FundingTradeExecute FundingTrade

type FundingTradeSnapshot struct {
	Snapshot []FundingTrade
}

func FTFromRaw(pair string, raw []interface{}) (t FundingTrade, err error) {
	if len(raw) >= 5 {
		t = FundingTrade{
			Pair:   pair,
			ID:     convert.I64ValOrZero(raw[0]),
			MTS:    convert.I64ValOrZero(raw[1]),
			Amount: convert.F64ValOrZero(raw[2]),
			Rate:   convert.F64ValOrZero(raw[3]),
			Period: convert.ToInt(raw[4]),
		}
		return
	}

	err = fmt.Errorf("data slice too short: %#v", raw)
	return
}

func FTEFromRaw(pair string, raw []interface{}) (FundingTradeExecute, error) {
	ft, err := FTFromRaw(pair, raw)
	if err != nil {
		return FundingTradeExecute{}, err
	}

	return FundingTradeExecute(ft), nil
}

func FTUFromRaw(pair string, raw []interface{}) (FundingTradeUpdate, error) {
	ft, err := FTFromRaw(pair, raw)
	if err != nil {
		return FundingTradeUpdate{}, err
	}

	return FundingTradeUpdate(ft), nil
}

func FTSnapshotFromRaw(pair string, raw [][]interface{}) (FundingTradeSnapshot, error) {
	if len(raw) == 0 {
		return FundingTradeSnapshot{}, fmt.Errorf("funding trade snapshot data slice too short:%#v", raw)
	}

	snapshot := make([]FundingTrade, 0)
	for _, v := range raw {
		t, err := FTFromRaw(pair, v)
		if err != nil {
			return FundingTradeSnapshot{}, err
		}
		snapshot = append(snapshot, t)
	}

	return FundingTradeSnapshot{Snapshot: snapshot}, nil
}
<commit_msg>funding trades model consisten naming, linter warning fixes<commit_after>package trades

import (
	"fmt"

	"github.com/bitfinexcom/bitfinex-api-go/pkg/convert"
)

// FundingTrade data structure for mapping funding/margin
// currency raw data with "f" prefix in SYMBOL from public feed
type FundingTrade struct {
	Symbol string
	ID     int64
	MTS    int64
	Amount float64
	Rate   float64
	Period int
}

type FundingTradeUpdate FundingTrade
type FundingTradeExecuted FundingTrade

type FundingTradeSnapshot struct {
	Snapshot []FundingTrade
}

// FTFromRaw maps raw data slice to instance of FundingTrade
func FTFromRaw(pair string, raw []interface{}) (t FundingTrade, err error) {
	if len(raw) >= 5 {
		t = FundingTrade{
			Symbol: pair,
			ID:     convert.I64ValOrZero(raw[0]),
			MTS:    convert.I64ValOrZero(raw[1]),
			Amount: convert.F64ValOrZero(raw[2]),
			Rate:   convert.F64ValOrZero(raw[3]),
			Period: convert.ToInt(raw[4]),
		}
		return
	}

	err = fmt.Errorf("data slice too short: %#v", raw)
	return
}

// FTEFromRaw maps raw data slice to instance of FundingTradeExecuted
func FTEFromRaw(pair string, raw []interface{}) (FundingTradeExecuted, error) {
	ft, err := FTFromRaw(pair, raw)
	if err != nil {
		return FundingTradeExecuted{}, err
	}

	return FundingTradeExecuted(ft), nil
}

// FTUFromRaw maps raw data slice to instance of FundingTradeUpdate
func FTUFromRaw(pair string, raw []interface{}) (FundingTradeUpdate, error) {
	ft, err := FTFromRaw(pair, raw)
	if err != nil {
		return FundingTradeUpdate{}, err
	}

	return FundingTradeUpdate(ft), nil
}

// FTSnapshotFromRaw maps raw data slice to funding trade data structures
func FTSnapshotFromRaw(pair string, raw [][]interface{}) (FundingTradeSnapshot, error) {
	if len(raw) == 0 {
		return FundingTradeSnapshot{}, fmt.Errorf("funding trade snapshot data slice too short:%#v", raw)
	}

	snapshot := make([]FundingTrade, 0)
	for _, v := range raw {
		t, err := FTFromRaw(pair, v)
		if err != nil {
			return FundingTradeSnapshot{}, err
		}
		snapshot = append(snapshot, t)
	}

	return FundingTradeSnapshot{Snapshot: snapshot}, nil
}
<|endoftext|>


<commit_before>package prometheus

import (
	"reflect"
	"testing"

	"k8s.io/client-go/pkg/api/v1"

	"github.com/coreos/prometheus-operator/pkg/client/monitoring/v1alpha1"
)

func TestStatefulSetLabelingAndAnnotations(t *testing.T) {
	labels := map[string]string{
		"testlabel": "testlabelvalue",
	}
	annotations := map[string]string{
		"testannotation": "testannotationvalue",
	}

	sset := makeStatefulSet(v1alpha1.Prometheus{
		ObjectMeta: v1.ObjectMeta{
			Labels:      labels,
			Annotations: annotations,
		},
	}, nil)

	if !reflect.DeepEqual(labels, sset.Labels) || !reflect.DeepEqual(annotations, sset.Annotations) {
		t.Fatal("Labels or Annotations are not properly being propagated to the StatefulSet")
	}
}
<commit_msg>Add license header to test file<commit_after>// Copyright 2016 The prometheus-operator 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 prometheus

import (
	"reflect"
	"testing"

	"k8s.io/client-go/pkg/api/v1"

	"github.com/coreos/prometheus-operator/pkg/client/monitoring/v1alpha1"
)

func TestStatefulSetLabelingAndAnnotations(t *testing.T) {
	labels := map[string]string{
		"testlabel": "testlabelvalue",
	}
	annotations := map[string]string{
		"testannotation": "testannotationvalue",
	}

	sset := makeStatefulSet(v1alpha1.Prometheus{
		ObjectMeta: v1.ObjectMeta{
			Labels:      labels,
			Annotations: annotations,
		},
	}, nil)

	if !reflect.DeepEqual(labels, sset.Labels) || !reflect.DeepEqual(annotations, sset.Annotations) {
		t.Fatal("Labels or Annotations are not properly being propagated to the StatefulSet")
	}
}
<|endoftext|>


<commit_before>package report

import (
	"sync"
	"time"

	"github.com/pion/interceptor"
	"github.com/pion/logging"
	"github.com/pion/rtcp"
)

// ReceiverInterceptorFactory is a interceptor.Factory for a ReceiverInterceptor
type ReceiverInterceptorFactory struct {
	opts []ReceiverOption
}

// NewInterceptor constructs a new ReceiverInterceptor
func (r *ReceiverInterceptorFactory) NewInterceptor(id string) (interceptor.Interceptor, error) {
	i := &ReceiverInterceptor{
		interval: 1 * time.Second,
		now:      time.Now,
		log:      logging.NewDefaultLoggerFactory().NewLogger("receiver_interceptor"),
		close:    make(chan struct{}),
	}

	for _, opt := range r.opts {
		if err := opt(i); err != nil {
			return nil, err
		}
	}

	return i, nil
}

// NewReceiverInterceptor returns a new ReceiverInterceptorFactory
func NewReceiverInterceptor(opts ...ReceiverOption) (*ReceiverInterceptorFactory, error) {
	return &ReceiverInterceptorFactory{opts}, nil
}

// ReceiverInterceptor interceptor generates receiver reports.
type ReceiverInterceptor struct {
	interceptor.NoOp
	interval time.Duration
	now      func() time.Time
	streams  sync.Map
	log      logging.LeveledLogger
	m        sync.Mutex
	wg       sync.WaitGroup
	close    chan struct{}
}

func (r *ReceiverInterceptor) isClosed() bool {
	select {
	case <-r.close:
		return true
	default:
		return false
	}
}

// Close closes the interceptor.
func (r *ReceiverInterceptor) Close() error {
	defer r.wg.Wait()
	r.m.Lock()
	defer r.m.Unlock()

	if !r.isClosed() {
		close(r.close)
	}

	return nil
}

// BindRTCPWriter lets you modify any outgoing RTCP packets. It is called once per PeerConnection. The returned method
// will be called once per packet batch.
func (r *ReceiverInterceptor) BindRTCPWriter(writer interceptor.RTCPWriter) interceptor.RTCPWriter {
	r.m.Lock()
	defer r.m.Unlock()

	if r.isClosed() {
		return writer
	}

	r.wg.Add(1)

	go r.loop(writer)

	return writer
}

func (r *ReceiverInterceptor) loop(rtcpWriter interceptor.RTCPWriter) {
	defer r.wg.Done()

	ticker := time.NewTicker(r.interval)
	defer ticker.Stop()
	for {
		select {
		case <-ticker.C:
			now := r.now()
			r.streams.Range(func(key, value interface{}) bool {
				stream := value.(*receiverStream)

				var pkts []rtcp.Packet

				pkts = append(pkts, stream.generateReport(now))

				if _, err := rtcpWriter.Write(pkts, interceptor.Attributes{}); err != nil {
					r.log.Warnf("failed sending: %+v", err)
				}

				return true
			})

		case <-r.close:
			return
		}
	}
}

// BindRemoteStream lets you modify any incoming RTP packets. It is called once for per RemoteStream. The returned method
// will be called once per rtp packet.
func (r *ReceiverInterceptor) BindRemoteStream(info *interceptor.StreamInfo, reader interceptor.RTPReader) interceptor.RTPReader {
	stream := newReceiverStream(info.SSRC, info.ClockRate)
	r.streams.Store(info.SSRC, stream)

	return interceptor.RTPReaderFunc(func(b []byte, a interceptor.Attributes) (int, interceptor.Attributes, error) {
		i, attr, err := reader.Read(b, a)
		if err != nil {
			return 0, nil, err
		}

		if attr == nil {
			attr = make(interceptor.Attributes)
		}
		header, err := attr.GetRTPHeader(b[:i])
		if err != nil {
			return 0, nil, err
		}

		stream.processRTP(r.now(), header)

		return i, attr, nil
	})
}

// UnbindLocalStream is called when the Stream is removed. It can be used to clean up any data related to that track.
func (r *ReceiverInterceptor) UnbindLocalStream(info *interceptor.StreamInfo) {
	r.streams.Delete(info.SSRC)
}

// BindRTCPReader lets you modify any incoming RTCP packets. It is called once per sender/receiver, however this might
// change in the future. The returned method will be called once per packet batch.
func (r *ReceiverInterceptor) BindRTCPReader(reader interceptor.RTCPReader) interceptor.RTCPReader {
	return interceptor.RTCPReaderFunc(func(b []byte, a interceptor.Attributes) (int, interceptor.Attributes, error) {
		i, attr, err := reader.Read(b, a)
		if err != nil {
			return 0, nil, err
		}

		if attr == nil {
			attr = make(interceptor.Attributes)
		}
		pkts, err := attr.GetRTCPPackets(b[:i])
		if err != nil {
			return 0, nil, err
		}

		for _, pkt := range pkts {
			if sr, ok := (pkt).(*rtcp.SenderReport); ok {
				value, ok := r.streams.Load(sr.SSRC)
				if !ok {
					continue
				}

				stream := value.(*receiverStream)
				stream.processSenderReport(r.now(), sr)
			}
		}

		return i, attr, nil
	})
}
<commit_msg>Improve performance of RTCP receiver report<commit_after>package report

import (
	"sync"
	"time"

	"github.com/pion/interceptor"
	"github.com/pion/logging"
	"github.com/pion/rtcp"
)

// ReceiverInterceptorFactory is a interceptor.Factory for a ReceiverInterceptor
type ReceiverInterceptorFactory struct {
	opts []ReceiverOption
}

// NewInterceptor constructs a new ReceiverInterceptor
func (r *ReceiverInterceptorFactory) NewInterceptor(id string) (interceptor.Interceptor, error) {
	i := &ReceiverInterceptor{
		interval: 1 * time.Second,
		now:      time.Now,
		log:      logging.NewDefaultLoggerFactory().NewLogger("receiver_interceptor"),
		close:    make(chan struct{}),
	}

	for _, opt := range r.opts {
		if err := opt(i); err != nil {
			return nil, err
		}
	}

	return i, nil
}

// NewReceiverInterceptor returns a new ReceiverInterceptorFactory
func NewReceiverInterceptor(opts ...ReceiverOption) (*ReceiverInterceptorFactory, error) {
	return &ReceiverInterceptorFactory{opts}, nil
}

// ReceiverInterceptor interceptor generates receiver reports.
type ReceiverInterceptor struct {
	interceptor.NoOp
	interval time.Duration
	now      func() time.Time
	streams  sync.Map
	log      logging.LeveledLogger
	m        sync.Mutex
	wg       sync.WaitGroup
	close    chan struct{}
}

func (r *ReceiverInterceptor) isClosed() bool {
	select {
	case <-r.close:
		return true
	default:
		return false
	}
}

// Close closes the interceptor.
func (r *ReceiverInterceptor) Close() error {
	defer r.wg.Wait()
	r.m.Lock()
	defer r.m.Unlock()

	if !r.isClosed() {
		close(r.close)
	}

	return nil
}

// BindRTCPWriter lets you modify any outgoing RTCP packets. It is called once per PeerConnection. The returned method
// will be called once per packet batch.
func (r *ReceiverInterceptor) BindRTCPWriter(writer interceptor.RTCPWriter) interceptor.RTCPWriter {
	r.m.Lock()
	defer r.m.Unlock()

	if r.isClosed() {
		return writer
	}

	r.wg.Add(1)

	go r.loop(writer)

	return writer
}

func (r *ReceiverInterceptor) loop(rtcpWriter interceptor.RTCPWriter) {
	defer r.wg.Done()

	ticker := time.NewTicker(r.interval)
	defer ticker.Stop()
	for {
		select {
		case <-ticker.C:
			now := r.now()
			r.streams.Range(func(key, value interface{}) bool {
				stream := value.(*receiverStream)

				if _, err := rtcpWriter.Write([]rtcp.Packet{stream.generateReport(now)}, interceptor.Attributes{}); err != nil {
					r.log.Warnf("failed sending: %+v", err)
				}

				return true
			})

		case <-r.close:
			return
		}
	}
}

// BindRemoteStream lets you modify any incoming RTP packets. It is called once for per RemoteStream. The returned method
// will be called once per rtp packet.
func (r *ReceiverInterceptor) BindRemoteStream(info *interceptor.StreamInfo, reader interceptor.RTPReader) interceptor.RTPReader {
	stream := newReceiverStream(info.SSRC, info.ClockRate)
	r.streams.Store(info.SSRC, stream)

	return interceptor.RTPReaderFunc(func(b []byte, a interceptor.Attributes) (int, interceptor.Attributes, error) {
		i, attr, err := reader.Read(b, a)
		if err != nil {
			return 0, nil, err
		}

		if attr == nil {
			attr = make(interceptor.Attributes)
		}
		header, err := attr.GetRTPHeader(b[:i])
		if err != nil {
			return 0, nil, err
		}

		stream.processRTP(r.now(), header)

		return i, attr, nil
	})
}

// UnbindLocalStream is called when the Stream is removed. It can be used to clean up any data related to that track.
func (r *ReceiverInterceptor) UnbindLocalStream(info *interceptor.StreamInfo) {
	r.streams.Delete(info.SSRC)
}

// BindRTCPReader lets you modify any incoming RTCP packets. It is called once per sender/receiver, however this might
// change in the future. The returned method will be called once per packet batch.
func (r *ReceiverInterceptor) BindRTCPReader(reader interceptor.RTCPReader) interceptor.RTCPReader {
	return interceptor.RTCPReaderFunc(func(b []byte, a interceptor.Attributes) (int, interceptor.Attributes, error) {
		i, attr, err := reader.Read(b, a)
		if err != nil {
			return 0, nil, err
		}

		if attr == nil {
			attr = make(interceptor.Attributes)
		}
		pkts, err := attr.GetRTCPPackets(b[:i])
		if err != nil {
			return 0, nil, err
		}

		for _, pkt := range pkts {
			if sr, ok := (pkt).(*rtcp.SenderReport); ok {
				value, ok := r.streams.Load(sr.SSRC)
				if !ok {
					continue
				}

				stream := value.(*receiverStream)
				stream.processSenderReport(r.now(), sr)
			}
		}

		return i, attr, nil
	})
}
<|endoftext|>


<commit_before>package pt

import (
	"math"
	"math/rand"
)

type Vector struct {
	X, Y, Z float64
}

func V(x, y, z float64) Vector {
	return Vector{x, y, z}
}

func RandomUnitVector(rnd *rand.Rand) Vector {
	for {
		var x, y, z float64
		if rnd == nil {
			x = rand.Float64()*2 - 1
			y = rand.Float64()*2 - 1
			z = rand.Float64()*2 - 1
		} else {
			x = rnd.Float64()*2 - 1
			y = rnd.Float64()*2 - 1
			z = rnd.Float64()*2 - 1
		}
		if x*x+y*y+z*z > 1 {
			continue
		}
		return Vector{x, y, z}.Normalize()
	}
}

func (a Vector) Length() float64 {
	return math.Sqrt(a.X*a.X + a.Y*a.Y + a.Z*a.Z)
}

func (a Vector) Dot(b Vector) float64 {
	return a.X*b.X + a.Y*b.Y + a.Z*b.Z
}

func (a Vector) Cross(b Vector) Vector {
	x := a.Y*b.Z - a.Z*b.Y
	y := a.Z*b.X - a.X*b.Z
	z := a.X*b.Y - a.Y*b.X
	return Vector{x, y, z}
}

func (a Vector) Normalize() Vector {
	d := a.Length()
	return Vector{a.X / d, a.Y / d, a.Z / d}
}

func (a Vector) Add(b Vector) Vector {
	return Vector{a.X + b.X, a.Y + b.Y, a.Z + b.Z}
}

func (a Vector) Sub(b Vector) Vector {
	return Vector{a.X - b.X, a.Y - b.Y, a.Z - b.Z}
}

func (a Vector) Mul(b Vector) Vector {
	return Vector{a.X * b.X, a.Y * b.Y, a.Z * b.Z}
}

func (a Vector) Div(b Vector) Vector {
	return Vector{a.X / b.X, a.Y / b.Y, a.Z / b.Z}
}

func (a Vector) MulScalar(b float64) Vector {
	return Vector{a.X * b, a.Y * b, a.Z * b}
}

func (a Vector) DivScalar(b float64) Vector {
	return Vector{a.X / b, a.Y / b, a.Z / b}
}

func (a Vector) Min(b Vector) Vector {
	return Vector{math.Min(a.X, b.X), math.Min(a.Y, b.Y), math.Min(a.Z, b.Z)}
}

func (a Vector) Max(b Vector) Vector {
	return Vector{math.Max(a.X, b.X), math.Max(a.Y, b.Y), math.Max(a.Z, b.Z)}
}

func (a Vector) MinAxis() Vector {
	x, y, z := math.Abs(a.X), math.Abs(a.Y), math.Abs(a.Z)
	switch {
	case x <= y && x <= z:
		return Vector{1, 0, 0}
	case y <= x && y <= z:
		return Vector{0, 1, 0}
	}
	return Vector{0, 0, 1}
}

func (a Vector) MinComponent() float64 {
	return math.Min(math.Min(a.X, a.Y), a.Z)
}

func (a Vector) MaxComponent() float64 {
	return math.Max(math.Max(a.X, a.Y), a.Z)
}

func (n Vector) Reflect(i Vector) Vector {
	return i.Sub(n.MulScalar(2 * n.Dot(i)))
}

func (n Vector) Refract(i Vector, n1, n2 float64) Vector {
	nr := n1 / n2
	cosI := -n.Dot(i)
	sinT2 := nr * nr * (1 - cosI*cosI)
	if sinT2 > 1 {
		return Vector{}
	}
	cosT := math.Sqrt(1 - sinT2)
	return i.MulScalar(nr).Add(n.MulScalar(nr*cosI - cosT))
}

func (n Vector) Reflectance(i Vector, n1, n2 float64) float64 {
	nr := n1 / n2
	cosI := -n.Dot(i)
	sinT2 := nr * nr * (1 - cosI*cosI)
	if sinT2 > 1 {
		return 1
	}
	cosT := math.Sqrt(1 - sinT2)
	rOrth := (n1*cosI - n2*cosT) / (n1*cosI + n2*cosT)
	rPar := (n2*cosI - n1*cosT) / (n2*cosI + n1*cosT)
	return (rOrth*rOrth + rPar*rPar) / 2
}
<commit_msg>Vector.Abs<commit_after>package pt

import (
	"math"
	"math/rand"
)

type Vector struct {
	X, Y, Z float64
}

func V(x, y, z float64) Vector {
	return Vector{x, y, z}
}

func RandomUnitVector(rnd *rand.Rand) Vector {
	for {
		var x, y, z float64
		if rnd == nil {
			x = rand.Float64()*2 - 1
			y = rand.Float64()*2 - 1
			z = rand.Float64()*2 - 1
		} else {
			x = rnd.Float64()*2 - 1
			y = rnd.Float64()*2 - 1
			z = rnd.Float64()*2 - 1
		}
		if x*x+y*y+z*z > 1 {
			continue
		}
		return Vector{x, y, z}.Normalize()
	}
}

func (a Vector) Length() float64 {
	return math.Sqrt(a.X*a.X + a.Y*a.Y + a.Z*a.Z)
}

func (a Vector) Dot(b Vector) float64 {
	return a.X*b.X + a.Y*b.Y + a.Z*b.Z
}

func (a Vector) Cross(b Vector) Vector {
	x := a.Y*b.Z - a.Z*b.Y
	y := a.Z*b.X - a.X*b.Z
	z := a.X*b.Y - a.Y*b.X
	return Vector{x, y, z}
}

func (a Vector) Normalize() Vector {
	d := a.Length()
	return Vector{a.X / d, a.Y / d, a.Z / d}
}

func (a Vector) Abs() Vector {
	return Vector{math.Abs(a.X), math.Abs(a.Y), math.Abs(a.Z)}
}

func (a Vector) Add(b Vector) Vector {
	return Vector{a.X + b.X, a.Y + b.Y, a.Z + b.Z}
}

func (a Vector) Sub(b Vector) Vector {
	return Vector{a.X - b.X, a.Y - b.Y, a.Z - b.Z}
}

func (a Vector) Mul(b Vector) Vector {
	return Vector{a.X * b.X, a.Y * b.Y, a.Z * b.Z}
}

func (a Vector) Div(b Vector) Vector {
	return Vector{a.X / b.X, a.Y / b.Y, a.Z / b.Z}
}

func (a Vector) MulScalar(b float64) Vector {
	return Vector{a.X * b, a.Y * b, a.Z * b}
}

func (a Vector) DivScalar(b float64) Vector {
	return Vector{a.X / b, a.Y / b, a.Z / b}
}

func (a Vector) Min(b Vector) Vector {
	return Vector{math.Min(a.X, b.X), math.Min(a.Y, b.Y), math.Min(a.Z, b.Z)}
}

func (a Vector) Max(b Vector) Vector {
	return Vector{math.Max(a.X, b.X), math.Max(a.Y, b.Y), math.Max(a.Z, b.Z)}
}

func (a Vector) MinAxis() Vector {
	x, y, z := math.Abs(a.X), math.Abs(a.Y), math.Abs(a.Z)
	switch {
	case x <= y && x <= z:
		return Vector{1, 0, 0}
	case y <= x && y <= z:
		return Vector{0, 1, 0}
	}
	return Vector{0, 0, 1}
}

func (a Vector) MinComponent() float64 {
	return math.Min(math.Min(a.X, a.Y), a.Z)
}

func (a Vector) MaxComponent() float64 {
	return math.Max(math.Max(a.X, a.Y), a.Z)
}

func (n Vector) Reflect(i Vector) Vector {
	return i.Sub(n.MulScalar(2 * n.Dot(i)))
}

func (n Vector) Refract(i Vector, n1, n2 float64) Vector {
	nr := n1 / n2
	cosI := -n.Dot(i)
	sinT2 := nr * nr * (1 - cosI*cosI)
	if sinT2 > 1 {
		return Vector{}
	}
	cosT := math.Sqrt(1 - sinT2)
	return i.MulScalar(nr).Add(n.MulScalar(nr*cosI - cosT))
}

func (n Vector) Reflectance(i Vector, n1, n2 float64) float64 {
	nr := n1 / n2
	cosI := -n.Dot(i)
	sinT2 := nr * nr * (1 - cosI*cosI)
	if sinT2 > 1 {
		return 1
	}
	cosT := math.Sqrt(1 - sinT2)
	rOrth := (n1*cosI - n2*cosT) / (n1*cosI + n2*cosT)
	rPar := (n2*cosI - n1*cosT) / (n2*cosI + n1*cosT)
	return (rOrth*rOrth + rPar*rPar) / 2
}
<|endoftext|>


<commit_before>package alerting

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"

	"github.com/grafana/grafana/pkg/bus"
	"github.com/grafana/grafana/pkg/components/simplejson"
	"github.com/grafana/grafana/pkg/infra/log"
	"github.com/grafana/grafana/pkg/models"
)

// DashAlertExtractor extracts alerts from the dashboard json.
type DashAlertExtractor struct {
	User  *models.SignedInUser
	Dash  *models.Dashboard
	OrgID int64
	log   log.Logger
}

// NewDashAlertExtractor returns a new DashAlertExtractor.
func NewDashAlertExtractor(dash *models.Dashboard, orgID int64, user *models.SignedInUser) *DashAlertExtractor {
	return &DashAlertExtractor{
		User:  user,
		Dash:  dash,
		OrgID: orgID,
		log:   log.New("alerting.extractor"),
	}
}

func (e *DashAlertExtractor) lookupQueryDataSource(panel *simplejson.Json, panelQuery *simplejson.Json) (*models.DataSource, error) {
	dsName := ""
	dsUid := ""

	datasource, ok := panelQuery.CheckGet("datasource")

	if !ok {
		fmt.Printf("no query level data soure \n")
		datasource = panel.Get("datasource")
	}

	if name, err := datasource.String(); err == nil {
		dsName = name
	} else if uid, ok := datasource.CheckGet("uid"); ok {
		dsUid = uid.MustString()
	}

	if dsName == "" && dsUid == "" {
		query := &models.GetDefaultDataSourceQuery{OrgId: e.OrgID}
		if err := bus.DispatchCtx(context.TODO(), query); err != nil {
			return nil, err
		}
		return query.Result, nil
	}

	query := &models.GetDataSourceQuery{Name: dsName, Uid: dsUid, OrgId: e.OrgID}
	if err := bus.DispatchCtx(context.TODO(), query); err != nil {
		return nil, err
	}

	return query.Result, nil
}

func findPanelQueryByRefID(panel *simplejson.Json, refID string) *simplejson.Json {
	for _, targetsObj := range panel.Get("targets").MustArray() {
		target := simplejson.NewFromAny(targetsObj)

		if target.Get("refId").MustString() == refID {
			return target
		}
	}
	return nil
}

func copyJSON(in json.Marshaler) (*simplejson.Json, error) {
	rawJSON, err := in.MarshalJSON()
	if err != nil {
		return nil, fmt.Errorf("JSON marshaling failed: %w", err)
	}

	return simplejson.NewJson(rawJSON)
}

func (e *DashAlertExtractor) getAlertFromPanels(jsonWithPanels *simplejson.Json, validateAlertFunc func(*models.Alert) bool, logTranslationFailures bool) ([]*models.Alert, error) {
	alerts := make([]*models.Alert, 0)

	for _, panelObj := range jsonWithPanels.Get("panels").MustArray() {
		panel := simplejson.NewFromAny(panelObj)

		collapsedJSON, collapsed := panel.CheckGet("collapsed")
		// check if the panel is collapsed
		if collapsed && collapsedJSON.MustBool() {
			// extract alerts from sub panels for collapsed panels
			alertSlice, err := e.getAlertFromPanels(panel, validateAlertFunc, logTranslationFailures)
			if err != nil {
				return nil, err
			}

			alerts = append(alerts, alertSlice...)
			continue
		}

		jsonAlert, hasAlert := panel.CheckGet("alert")

		if !hasAlert {
			continue
		}

		panelID, err := panel.Get("id").Int64()
		if err != nil {
			return nil, ValidationError{Reason: "A numeric panel id property is missing"}
		}

		addIdentifiersToValidationError := func(err error) error {
			if err == nil {
				return nil
			}

			var validationErr ValidationError
			if ok := errors.As(err, &validationErr); ok {
				ve := ValidationError{
					Reason:  validationErr.Reason,
					Err:     validationErr.Err,
					PanelID: panelID,
				}
				if e.Dash != nil {
					ve.DashboardID = e.Dash.Id
				}
				return ve
			}
			return err
		}

		// backward compatibility check, can be removed later
		enabled, hasEnabled := jsonAlert.CheckGet("enabled")
		if hasEnabled && !enabled.MustBool() {
			continue
		}

		frequency, err := getTimeDurationStringToSeconds(jsonAlert.Get("frequency").MustString())
		if err != nil {
			return nil, addIdentifiersToValidationError(ValidationError{Reason: err.Error()})
		}

		rawFor := jsonAlert.Get("for").MustString()

		forValue, err := getForValue(rawFor)
		if err != nil {
			return nil, addIdentifiersToValidationError(err)
		}

		alert := &models.Alert{
			DashboardId: e.Dash.Id,
			OrgId:       e.OrgID,
			PanelId:     panelID,
			Id:          jsonAlert.Get("id").MustInt64(),
			Name:        jsonAlert.Get("name").MustString(),
			Handler:     jsonAlert.Get("handler").MustInt64(),
			Message:     jsonAlert.Get("message").MustString(),
			Frequency:   frequency,
			For:         forValue,
		}

		for _, condition := range jsonAlert.Get("conditions").MustArray() {
			jsonCondition := simplejson.NewFromAny(condition)

			jsonQuery := jsonCondition.Get("query")
			queryRefID := jsonQuery.Get("params").MustArray()[0].(string)
			panelQuery := findPanelQueryByRefID(panel, queryRefID)

			if panelQuery == nil {
				reason := fmt.Sprintf("Alert on PanelId: %v refers to query(%s) that cannot be found", alert.PanelId, queryRefID)
				return nil, ValidationError{Reason: reason}
			}

			datasource, err := e.lookupQueryDataSource(panel, panelQuery)
			if err != nil {
				return nil, err
			}

			dsFilterQuery := models.DatasourcesPermissionFilterQuery{
				User:        e.User,
				Datasources: []*models.DataSource{datasource},
			}

			if err := bus.Dispatch(&dsFilterQuery); err != nil {
				if !errors.Is(err, bus.ErrHandlerNotFound) {
					return nil, err
				}
			} else {
				if len(dsFilterQuery.Result) == 0 {
					return nil, models.ErrDataSourceAccessDenied
				}
			}

			jsonQuery.SetPath([]string{"datasourceId"}, datasource.Id)

			if interval, err := panel.Get("interval").String(); err == nil {
				panelQuery.Set("interval", interval)
			}

			jsonQuery.Set("model", panelQuery.Interface())
		}

		alert.Settings = jsonAlert

		// validate
		_, err = NewRuleFromDBAlert(alert, logTranslationFailures)
		if err != nil {
			return nil, err
		}

		if !validateAlertFunc(alert) {
			return nil, ValidationError{Reason: fmt.Sprintf("Panel id is not correct, alertName=%v, panelId=%v", alert.Name, alert.PanelId)}
		}

		alerts = append(alerts, alert)
	}

	return alerts, nil
}

func validateAlertRule(alert *models.Alert) bool {
	return alert.ValidToSave()
}

// GetAlerts extracts alerts from the dashboard json and does full validation on the alert json data.
func (e *DashAlertExtractor) GetAlerts() ([]*models.Alert, error) {
	return e.extractAlerts(validateAlertRule, true)
}

func (e *DashAlertExtractor) extractAlerts(validateFunc func(alert *models.Alert) bool, logTranslationFailures bool) ([]*models.Alert, error) {
	dashboardJSON, err := copyJSON(e.Dash.Data)
	if err != nil {
		return nil, err
	}

	alerts := make([]*models.Alert, 0)

	// We extract alerts from rows to be backwards compatible
	// with the old dashboard json model.
	rows := dashboardJSON.Get("rows").MustArray()
	if len(rows) > 0 {
		for _, rowObj := range rows {
			row := simplejson.NewFromAny(rowObj)
			a, err := e.getAlertFromPanels(row, validateFunc, logTranslationFailures)
			if err != nil {
				return nil, err
			}

			alerts = append(alerts, a...)
		}
	} else {
		a, err := e.getAlertFromPanels(dashboardJSON, validateFunc, logTranslationFailures)
		if err != nil {
			return nil, err
		}

		alerts = append(alerts, a...)
	}

	e.log.Debug("Extracted alerts from dashboard", "alertCount", len(alerts))
	return alerts, nil
}

// ValidateAlerts validates alerts in the dashboard json but does not require a valid dashboard id
// in the first validation pass.
func (e *DashAlertExtractor) ValidateAlerts() error {
	_, err := e.extractAlerts(func(alert *models.Alert) bool {
		return alert.OrgId != 0 && alert.PanelId != 0
	}, false)
	return err
}
<commit_msg>remove println (#41139)<commit_after>package alerting

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"

	"github.com/grafana/grafana/pkg/bus"
	"github.com/grafana/grafana/pkg/components/simplejson"
	"github.com/grafana/grafana/pkg/infra/log"
	"github.com/grafana/grafana/pkg/models"
)

// DashAlertExtractor extracts alerts from the dashboard json.
type DashAlertExtractor struct {
	User  *models.SignedInUser
	Dash  *models.Dashboard
	OrgID int64
	log   log.Logger
}

// NewDashAlertExtractor returns a new DashAlertExtractor.
func NewDashAlertExtractor(dash *models.Dashboard, orgID int64, user *models.SignedInUser) *DashAlertExtractor {
	return &DashAlertExtractor{
		User:  user,
		Dash:  dash,
		OrgID: orgID,
		log:   log.New("alerting.extractor"),
	}
}

func (e *DashAlertExtractor) lookupQueryDataSource(panel *simplejson.Json, panelQuery *simplejson.Json) (*models.DataSource, error) {
	dsName := ""
	dsUid := ""

	datasource, ok := panelQuery.CheckGet("datasource")

	if !ok {
		datasource = panel.Get("datasource")
	}

	if name, err := datasource.String(); err == nil {
		dsName = name
	} else if uid, ok := datasource.CheckGet("uid"); ok {
		dsUid = uid.MustString()
	}

	if dsName == "" && dsUid == "" {
		query := &models.GetDefaultDataSourceQuery{OrgId: e.OrgID}
		if err := bus.DispatchCtx(context.TODO(), query); err != nil {
			return nil, err
		}
		return query.Result, nil
	}

	query := &models.GetDataSourceQuery{Name: dsName, Uid: dsUid, OrgId: e.OrgID}
	if err := bus.DispatchCtx(context.TODO(), query); err != nil {
		return nil, err
	}

	return query.Result, nil
}

func findPanelQueryByRefID(panel *simplejson.Json, refID string) *simplejson.Json {
	for _, targetsObj := range panel.Get("targets").MustArray() {
		target := simplejson.NewFromAny(targetsObj)

		if target.Get("refId").MustString() == refID {
			return target
		}
	}
	return nil
}

func copyJSON(in json.Marshaler) (*simplejson.Json, error) {
	rawJSON, err := in.MarshalJSON()
	if err != nil {
		return nil, fmt.Errorf("JSON marshaling failed: %w", err)
	}

	return simplejson.NewJson(rawJSON)
}

func (e *DashAlertExtractor) getAlertFromPanels(jsonWithPanels *simplejson.Json, validateAlertFunc func(*models.Alert) bool, logTranslationFailures bool) ([]*models.Alert, error) {
	alerts := make([]*models.Alert, 0)

	for _, panelObj := range jsonWithPanels.Get("panels").MustArray() {
		panel := simplejson.NewFromAny(panelObj)

		collapsedJSON, collapsed := panel.CheckGet("collapsed")
		// check if the panel is collapsed
		if collapsed && collapsedJSON.MustBool() {
			// extract alerts from sub panels for collapsed panels
			alertSlice, err := e.getAlertFromPanels(panel, validateAlertFunc, logTranslationFailures)
			if err != nil {
				return nil, err
			}

			alerts = append(alerts, alertSlice...)
			continue
		}

		jsonAlert, hasAlert := panel.CheckGet("alert")

		if !hasAlert {
			continue
		}

		panelID, err := panel.Get("id").Int64()
		if err != nil {
			return nil, ValidationError{Reason: "A numeric panel id property is missing"}
		}

		addIdentifiersToValidationError := func(err error) error {
			if err == nil {
				return nil
			}

			var validationErr ValidationError
			if ok := errors.As(err, &validationErr); ok {
				ve := ValidationError{
					Reason:  validationErr.Reason,
					Err:     validationErr.Err,
					PanelID: panelID,
				}
				if e.Dash != nil {
					ve.DashboardID = e.Dash.Id
				}
				return ve
			}
			return err
		}

		// backward compatibility check, can be removed later
		enabled, hasEnabled := jsonAlert.CheckGet("enabled")
		if hasEnabled && !enabled.MustBool() {
			continue
		}

		frequency, err := getTimeDurationStringToSeconds(jsonAlert.Get("frequency").MustString())
		if err != nil {
			return nil, addIdentifiersToValidationError(ValidationError{Reason: err.Error()})
		}

		rawFor := jsonAlert.Get("for").MustString()

		forValue, err := getForValue(rawFor)
		if err != nil {
			return nil, addIdentifiersToValidationError(err)
		}

		alert := &models.Alert{
			DashboardId: e.Dash.Id,
			OrgId:       e.OrgID,
			PanelId:     panelID,
			Id:          jsonAlert.Get("id").MustInt64(),
			Name:        jsonAlert.Get("name").MustString(),
			Handler:     jsonAlert.Get("handler").MustInt64(),
			Message:     jsonAlert.Get("message").MustString(),
			Frequency:   frequency,
			For:         forValue,
		}

		for _, condition := range jsonAlert.Get("conditions").MustArray() {
			jsonCondition := simplejson.NewFromAny(condition)

			jsonQuery := jsonCondition.Get("query")
			queryRefID := jsonQuery.Get("params").MustArray()[0].(string)
			panelQuery := findPanelQueryByRefID(panel, queryRefID)

			if panelQuery == nil {
				reason := fmt.Sprintf("Alert on PanelId: %v refers to query(%s) that cannot be found", alert.PanelId, queryRefID)
				return nil, ValidationError{Reason: reason}
			}

			datasource, err := e.lookupQueryDataSource(panel, panelQuery)
			if err != nil {
				return nil, err
			}

			dsFilterQuery := models.DatasourcesPermissionFilterQuery{
				User:        e.User,
				Datasources: []*models.DataSource{datasource},
			}

			if err := bus.Dispatch(&dsFilterQuery); err != nil {
				if !errors.Is(err, bus.ErrHandlerNotFound) {
					return nil, err
				}
			} else {
				if len(dsFilterQuery.Result) == 0 {
					return nil, models.ErrDataSourceAccessDenied
				}
			}

			jsonQuery.SetPath([]string{"datasourceId"}, datasource.Id)

			if interval, err := panel.Get("interval").String(); err == nil {
				panelQuery.Set("interval", interval)
			}

			jsonQuery.Set("model", panelQuery.Interface())
		}

		alert.Settings = jsonAlert

		// validate
		_, err = NewRuleFromDBAlert(alert, logTranslationFailures)
		if err != nil {
			return nil, err
		}

		if !validateAlertFunc(alert) {
			return nil, ValidationError{Reason: fmt.Sprintf("Panel id is not correct, alertName=%v, panelId=%v", alert.Name, alert.PanelId)}
		}

		alerts = append(alerts, alert)
	}

	return alerts, nil
}

func validateAlertRule(alert *models.Alert) bool {
	return alert.ValidToSave()
}

// GetAlerts extracts alerts from the dashboard json and does full validation on the alert json data.
func (e *DashAlertExtractor) GetAlerts() ([]*models.Alert, error) {
	return e.extractAlerts(validateAlertRule, true)
}

func (e *DashAlertExtractor) extractAlerts(validateFunc func(alert *models.Alert) bool, logTranslationFailures bool) ([]*models.Alert, error) {
	dashboardJSON, err := copyJSON(e.Dash.Data)
	if err != nil {
		return nil, err
	}

	alerts := make([]*models.Alert, 0)

	// We extract alerts from rows to be backwards compatible
	// with the old dashboard json model.
	rows := dashboardJSON.Get("rows").MustArray()
	if len(rows) > 0 {
		for _, rowObj := range rows {
			row := simplejson.NewFromAny(rowObj)
			a, err := e.getAlertFromPanels(row, validateFunc, logTranslationFailures)
			if err != nil {
				return nil, err
			}

			alerts = append(alerts, a...)
		}
	} else {
		a, err := e.getAlertFromPanels(dashboardJSON, validateFunc, logTranslationFailures)
		if err != nil {
			return nil, err
		}

		alerts = append(alerts, a...)
	}

	e.log.Debug("Extracted alerts from dashboard", "alertCount", len(alerts))
	return alerts, nil
}

// ValidateAlerts validates alerts in the dashboard json but does not require a valid dashboard id
// in the first validation pass.
func (e *DashAlertExtractor) ValidateAlerts() error {
	_, err := e.extractAlerts(func(alert *models.Alert) bool {
		return alert.OrgId != 0 && alert.PanelId != 0
	}, false)
	return err
}
<|endoftext|>


<commit_before>package registry

import (
	"testing"

	kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"

	config "github.com/openshift/origin/pkg/config/api"
	template "github.com/openshift/origin/pkg/template/api"
)

func TestNewRESTInvalidType(t *testing.T) {
	storage := NewREST()
	_, err := storage.Create(nil, &kapi.Pod{})
	if err == nil {
		t.Errorf("Expected type error.")
	}
}

func TestNewRESTDefaultsName(t *testing.T) {
	storage := NewREST()
	obj, err := storage.Create(nil, &template.Template{
		ObjectMeta: kapi.ObjectMeta{
			Name: "test",
		},
	})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	_, ok := obj.(*config.Config)
	if !ok {
		t.Fatalf("unexpected return object: %#v", obj)
	}
}

func TestNewRESTTemplateLabels(t *testing.T) {
	testLabels := map[string]string{
		"label1": "value1",
		"label2": "value2",
	}
	storage := NewREST()
	obj, err := storage.Create(nil, &template.Template{
		ObjectMeta: kapi.ObjectMeta{
			Name: "test",
		},
		Objects: []runtime.Object{
			&kapi.Service{
				ObjectMeta: kapi.ObjectMeta{
					Name: "test-service",
				},
				Spec: kapi.ServiceSpec{
					Port:            80,
					Protocol:        kapi.ProtocolTCP,
					SessionAffinity: kapi.AffinityTypeNone,
				},
			},
		},
		ObjectLabels: testLabels,
	})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	config, ok := obj.(*config.Config)
	if !ok {
		t.Fatalf("unexpected return object: %#v", obj)
	}
	svc, ok := config.Items[0].(*kapi.Service)
	if !ok {
		t.Fatalf("Unexpected object in config: %#v", svc)
	}
	for k, v := range testLabels {
		value, ok := svc.Labels[k]
		if !ok {
			t.Fatalf("Missing output label: %s", k)
		}
		if value != v {
			t.Fatalf("Unexpected label value: %s", value)
		}
	}
}
<commit_msg>Add test to exercise invalid parameter in Template<commit_after>package registry

import (
	"testing"

	kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"

	config "github.com/openshift/origin/pkg/config/api"
	template "github.com/openshift/origin/pkg/template/api"
)

func TestNewRESTInvalidType(t *testing.T) {
	storage := NewREST()
	_, err := storage.Create(nil, &kapi.Pod{})
	if err == nil {
		t.Errorf("Expected type error.")
	}
}

func TestNewRESTDefaultsName(t *testing.T) {
	storage := NewREST()
	obj, err := storage.Create(nil, &template.Template{
		ObjectMeta: kapi.ObjectMeta{
			Name: "test",
		},
	})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	_, ok := obj.(*config.Config)
	if !ok {
		t.Fatalf("unexpected return object: %#v", obj)
	}
}

func TestNewRESTInvalidParameter(t *testing.T) {
	storage := NewREST()
	_, err := storage.Create(nil, &template.Template{
		ObjectMeta: kapi.ObjectMeta{
			Name: "test",
		},
		Parameters: []template.Parameter{
			{
				Name:     "TEST_PARAM",
				Generate: "[a-z0-Z0-9]{8}",
			},
		},
		Objects: []runtime.Object{},
	})
	if err == nil {
		t.Fatalf("Expected 'invalid parameter error', got nothing")
	}
}

func TestNewRESTTemplateLabels(t *testing.T) {
	testLabels := map[string]string{
		"label1": "value1",
		"label2": "value2",
	}
	storage := NewREST()
	obj, err := storage.Create(nil, &template.Template{
		ObjectMeta: kapi.ObjectMeta{
			Name: "test",
		},
		Objects: []runtime.Object{
			&kapi.Service{
				ObjectMeta: kapi.ObjectMeta{
					Name: "test-service",
				},
				Spec: kapi.ServiceSpec{
					Port:            80,
					Protocol:        kapi.ProtocolTCP,
					SessionAffinity: kapi.AffinityTypeNone,
				},
			},
		},
		ObjectLabels: testLabels,
	})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	config, ok := obj.(*config.Config)
	if !ok {
		t.Fatalf("unexpected return object: %#v", obj)
	}
	svc, ok := config.Items[0].(*kapi.Service)
	if !ok {
		t.Fatalf("Unexpected object in config: %#v", svc)
	}
	for k, v := range testLabels {
		value, ok := svc.Labels[k]
		if !ok {
			t.Fatalf("Missing output label: %s", k)
		}
		if value != v {
			t.Fatalf("Unexpected label value: %s", value)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2013 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 bitset implements bitsets, a mapping
	between non-negative integers and boolean values. It should be more
	efficient than map[uint] bool.

	It provides methods for setting, clearing, flipping, and testing
	individual integers.

	But it also provides set intersection, union, difference,
	complement, and symmetric operations, as well as tests to
	check whether any, all, or no bits are set, and querying a
	bitset's current length and number of postive bits.

	BitSets are expanded to the size of the largest set bit; the
	memory allocation is approximately Max bits, where Max is
	the largest set bit. BitSets are never shrunk. On creation,
	a hint can be given for the number of bits that will be used.

    Many of the methods, including Set,Clear, and Flip, return
	a BitSet pointer, which allows for chaining.

	Example use:

	import "bitset"
	var b BitSet
	b.Set(10).Set(11)
	if b.Test(1000) {
		b.Clear(1000)
	}
	if B.Intersection(bitset.New(100).Set(10)).Count() > 1 {
		fmt.Println("Intersection works.")
	}

	As an alternative to BitSets, one should check out the 'big' package,
	which provides a (less set-theoretical) view of bitsets.

*/
package bitset

import (
	"bytes"
	"fmt"
	"math"
)

// Word size of a bit set
const wordSize = uint(32)

// Mask for cleaning last word
const allBits uint32 = 0xffffffff

// for laster arith.
const log2WordSize = uint(5)

// The zero value of a BitSet is an empty set of length 0.
type BitSet struct {
	length uint
	set    []uint32
}

type BitSetError string

// fixup b.set to be non-nil and return the field value
func (b *BitSet) safeSet() []uint32 {
	if b.set == nil {
		b.set = make([]uint32, wordsNeeded(0))
	}
	return b.set
}

func wordsNeeded(i uint) uint {
	if i == math.MaxUint32 {
		return math.MaxUint32 >> log2WordSize
	} else if i == 0 {
		return 1
	}
	return (i + (wordSize - 1)) >> log2WordSize
}

func New(length uint) *BitSet {
	return &BitSet{length, make([]uint32, wordsNeeded(length))}
}

func (b *BitSet) Cap() uint {
	return uint(math.MaxUint32)
}

func (b *BitSet) Len() uint {
	return b.length
}

//
func (b *BitSet) extendSetMaybe(i uint) {
	if i >= b.length { // if we need more bits, make 'em
		nsize := wordsNeeded(i + 1)
		if b.set == nil {
			b.set = make([]uint32, nsize)
		} else if uint(len(b.set)) < nsize {
			newset := make([]uint32, nsize)
			copy(newset, b.set)
			b.set = newset
		}
		b.length = i
	}
}

/// Test whether bit i is set.
func (b *BitSet) Test(i uint) bool {
	if i >= b.length {
		return false
	}
	return ((b.set[i>>log2WordSize] & (1 << (i & (wordSize - 1)))) != 0)
}

// Set bit i to 1
func (b *BitSet) Set(i uint) *BitSet {
	b.extendSetMaybe(i)
	//fmt.Printf("length in bits: %d, real size of sets: %d, bits: %d, index: %d\n", b.length, len(b.set), i, i>>log2WordSize)
	b.set[i>>log2WordSize] |= (1 << (i & (wordSize - 1)))
	return b
}

// Clear bit i to 0
func (b *BitSet) Clear(i uint) *BitSet {
	if i >= b.length {
		return b
	}
	b.set[i>>log2WordSize] &^= 1 << (i & (wordSize - 1))
	return b
}

// Set bit i to value
func (b *BitSet) SetTo(i uint, value bool) *BitSet {
	if value {
		return b.Set(i)
	}
	return b.Clear(i)
}

// Flip bit at i
func (b *BitSet) Flip(i uint) *BitSet {
	if i >= b.length {
		return b.Set(i)
	}
	b.set[i>>log2WordSize] ^= 1 << (i & (wordSize - 1))
	return b
}

// Clear entire BitSet
func (b *BitSet) ClearAll() *BitSet {
	if b != nil && b.set != nil {
		for i := range b.set {
			b.set[i] = 0
		}
	}
	return b
}

// Query words used in a bit set
func (b *BitSet) wordCount() uint {
	return wordsNeeded(b.length)
}

// Clone this BitSet
func (b *BitSet) Clone() *BitSet {
	c := New(b.length)
	copy(c.set, b.safeSet())
	return c
}

// Copy this BitSet into a destination BitSet
// Returning the size of the destination BitSet
// like array copy
func (b *BitSet) Copy(c *BitSet) (count uint) {
	if c == nil {
		return
	}
	copy(c.set, b.safeSet())
	count = c.length
	if b.length < c.length {
		count = b.length
	}
	return
}

// From Wikipedia: http://en.wikipedia.org/wiki/Hamming_weight
const m1 uint32 = 0x55555555 //binary: 0101...
const m2 uint32 = 0x33333333 //binary: 00110011..
const m4 uint32 = 0x0f0f0f0f //binary:  4 zeros,  4 ones ...

// From Wikipedia: count number of set bits.
// This is algorithm popcount_2 in the article retrieved May 9, 2011
func popCountUint32(x uint32) uint32 {
	x -= (x >> 1) & m1             //put count of each 2 bits into those 2 bits
	x = (x & m2) + ((x >> 2) & m2) //put count of each 4 bits into those 4 bits
	x = (x + (x >> 4)) & m4        //put count of each 8 bits into those 8 bits
	x += x >> 8                    //put count of each 16 bits into their lowest 8 bits
	x += x >> 16                   //put count of each 32 bits into their lowest 8 bits
	//x += x >> 32;  //put count of each 64 bits into their lowest 8 bits
	return x & 0x7f
}

// Count (number of set bits)
func (b *BitSet) Count() uint {
	if b != nil && b.set != nil {
		cnt := uint32(0)
		for _, word := range b.set {
			cnt += popCountUint32(word)
		}
		return uint(cnt)
	}
	return 0
}

// Test the equvalence of two BitSets.
// False if they are of different sizes, otherwise true
// only if all the same bits are set
func (b *BitSet) Equal(c *BitSet) bool {
	if c == nil {
		return false
	}
	if b.length != c.length {
		return false
	}
	for p, v := range b.safeSet() {
		if c.set[p] != v {
			return false
		}
	}
	return true
}

func panicIfNull(b *BitSet) {
	if b == nil {
		panic(BitSetError("BitSet must not be null"))
	}
}

// Difference of base set and other set
// This is the BitSet equivalent of &^ (and not)
func (b *BitSet) Difference(compare *BitSet) (result *BitSet) {
	panicIfNull(b)
	panicIfNull(compare)
	result = b.Clone() // clone b (in case b is bigger than compare)
	szl := compare.wordCount()
	for i, word := range b.safeSet() {
		if uint(i) >= szl {
			break
		}
		result.set[i] = word &^ compare.set[i]
	}
	return
}

// Convenience function: return two bitsets ordered by
// increasing length. Note: neither can be nil
func sortByLength(a *BitSet, b *BitSet) (ap *BitSet, bp *BitSet) {
	if a.length <= b.length {
		ap, bp = a, b
	} else {
		ap, bp = b, a
	}
	return
}

// Intersection of base set and other set
// This is the BitSet equivalent of & (and)
func (b *BitSet) Intersection(compare *BitSet) (result *BitSet) {
	panicIfNull(b)
	panicIfNull(compare)
	b, compare = sortByLength(b, compare)
	result = New(b.length)
	for i, word := range b.safeSet() {
		result.set[i] = word & compare.set[i]
	}
	return
}

// Union of base set and other set
// This is the BitSet equivalent of | (or)
func (b *BitSet) Union(compare *BitSet) (result *BitSet) {
	panicIfNull(b)
	panicIfNull(compare)
	b, compare = sortByLength(b, compare)
	result = compare.Clone()
	szl := compare.wordCount()
	for i, word := range b.safeSet() {
		if uint(i) >= szl {
			break
		}
		result.set[i] = word | compare.set[i]
	}
	return
}

// SymmetricDifference of base set and other set
// This is the BitSet equivalent of ^ (xor)
func (b *BitSet) SymmetricDifference(compare *BitSet) (result *BitSet) {
	panicIfNull(b)
	panicIfNull(compare)
	b, compare = sortByLength(b, compare)
	// compare is bigger, so clone it
	result = compare.Clone()
	szl := b.wordCount()
	for i, word := range b.safeSet() {
		if uint(i) >= szl {
			break
		}
		result.set[i] = word ^ compare.set[i]
	}
	return
}

// Is the length an exact multiple of word sizes?
func (b *BitSet) isEven() bool {
	return (b.length % wordSize) == 0
}

// Clean last word by setting unused bits to 0
func (b *BitSet) cleanLastWord() {
	if !b.isEven() {
		b.set[wordsNeeded(b.length)-1] &= (allBits >> (wordSize - (b.length % wordSize)))
	}
}

// Return the (local) Complement of a biset (up to length bits)
func (b *BitSet) Complement() (result *BitSet) {
	panicIfNull(b)
	result = New(b.length)
	for i, word := range b.safeSet() {
		result.set[i] = ^(word)
	}
	result.cleanLastWord()
	return
}

// Returns true if all bits are set, false otherwise
func (b *BitSet) All() bool {
	panicIfNull(b)
	return b.Count() == b.length
}

// Return true if no bit is set, false otherwise
func (b *BitSet) None() bool {
	panicIfNull(b)
	if b != nil && b.set != nil {
		for _, word := range b.set {
			if word > 0 {
				return false
			}
		}
		return true
	}
	return true
}

// Return true if any bit is set, false otherwise
func (b *BitSet) Any() bool {
	panicIfNull(b)
	return !b.None()
}

// Dump as bits
func (b *BitSet) DumpAsBits() string {
	buffer := bytes.NewBufferString("")
	b.safeSet()
	i := int(wordsNeeded(b.length) - 1)
	for ; i >= 0; i-- {
		fmt.Fprintf(buffer, "%032b.", b.set[i])
	}
	return string(buffer.Bytes())
}
<commit_msg>fix off by one error<commit_after>// Copyright 2013 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 bitset implements bitsets, a mapping
	between non-negative integers and boolean values. It should be more
	efficient than map[uint] bool.

	It provides methods for setting, clearing, flipping, and testing
	individual integers.

	But it also provides set intersection, union, difference,
	complement, and symmetric operations, as well as tests to
	check whether any, all, or no bits are set, and querying a
	bitset's current length and number of postive bits.

	BitSets are expanded to the size of the largest set bit; the
	memory allocation is approximately Max bits, where Max is
	the largest set bit. BitSets are never shrunk. On creation,
	a hint can be given for the number of bits that will be used.

    Many of the methods, including Set,Clear, and Flip, return
	a BitSet pointer, which allows for chaining.

	Example use:

	import "bitset"
	var b BitSet
	b.Set(10).Set(11)
	if b.Test(1000) {
		b.Clear(1000)
	}
	if B.Intersection(bitset.New(100).Set(10)).Count() > 1 {
		fmt.Println("Intersection works.")
	}

	As an alternative to BitSets, one should check out the 'big' package,
	which provides a (less set-theoretical) view of bitsets.

*/
package bitset

import (
	"bytes"
	"fmt"
	"math"
)

// Word size of a bit set
const wordSize = uint(32)

// Mask for cleaning last word
const allBits uint32 = 0xffffffff

// for laster arith.
const log2WordSize = uint(5)

// The zero value of a BitSet is an empty set of length 0.
type BitSet struct {
	length uint
	set    []uint32
}

type BitSetError string

// fixup b.set to be non-nil and return the field value
func (b *BitSet) safeSet() []uint32 {
	if b.set == nil {
		b.set = make([]uint32, wordsNeeded(0))
	}
	return b.set
}

func wordsNeeded(i uint) uint {
	if i == math.MaxUint32 {
		return math.MaxUint32 >> log2WordSize
	} else if i == 0 {
		return 1
	}
	return (i + (wordSize - 1)) >> log2WordSize
}

func New(length uint) *BitSet {
	return &BitSet{length, make([]uint32, wordsNeeded(length))}
}

func (b *BitSet) Cap() uint {
	return uint(math.MaxUint32)
}

func (b *BitSet) Len() uint {
	return b.length
}

//
func (b *BitSet) extendSetMaybe(i uint) {
	if i >= b.length { // if we need more bits, make 'em
		nsize := wordsNeeded(i + 1)
		if b.set == nil {
			b.set = make([]uint32, nsize)
		} else if uint(len(b.set)) < nsize {
			newset := make([]uint32, nsize)
			copy(newset, b.set)
			b.set = newset
		}
		b.length = i+1
	}
}

/// Test whether bit i is set.
func (b *BitSet) Test(i uint) bool {
	if i >= b.length {
		return false
	}
	return ((b.set[i>>log2WordSize] & (1 << (i & (wordSize - 1)))) != 0)
}

// Set bit i to 1
func (b *BitSet) Set(i uint) *BitSet {
	b.extendSetMaybe(i)
	//fmt.Printf("length in bits: %d, real size of sets: %d, bits: %d, index: %d\n", b.length, len(b.set), i, i>>log2WordSize)
	b.set[i>>log2WordSize] |= (1 << (i & (wordSize - 1)))
	return b
}

// Clear bit i to 0
func (b *BitSet) Clear(i uint) *BitSet {
	if i >= b.length {
		return b
	}
	b.set[i>>log2WordSize] &^= 1 << (i & (wordSize - 1))
	return b
}

// Set bit i to value
func (b *BitSet) SetTo(i uint, value bool) *BitSet {
	if value {
		return b.Set(i)
	}
	return b.Clear(i)
}

// Flip bit at i
func (b *BitSet) Flip(i uint) *BitSet {
	if i >= b.length {
		return b.Set(i)
	}
	b.set[i>>log2WordSize] ^= 1 << (i & (wordSize - 1))
	return b
}

// Clear entire BitSet
func (b *BitSet) ClearAll() *BitSet {
	if b != nil && b.set != nil {
		for i := range b.set {
			b.set[i] = 0
		}
	}
	return b
}

// Query words used in a bit set
func (b *BitSet) wordCount() uint {
	return wordsNeeded(b.length)
}

// Clone this BitSet
func (b *BitSet) Clone() *BitSet {
	c := New(b.length)
	copy(c.set, b.safeSet())
	return c
}

// Copy this BitSet into a destination BitSet
// Returning the size of the destination BitSet
// like array copy
func (b *BitSet) Copy(c *BitSet) (count uint) {
	if c == nil {
		return
	}
	copy(c.set, b.safeSet())
	count = c.length
	if b.length < c.length {
		count = b.length
	}
	return
}

// From Wikipedia: http://en.wikipedia.org/wiki/Hamming_weight
const m1 uint32 = 0x55555555 //binary: 0101...
const m2 uint32 = 0x33333333 //binary: 00110011..
const m4 uint32 = 0x0f0f0f0f //binary:  4 zeros,  4 ones ...

// From Wikipedia: count number of set bits.
// This is algorithm popcount_2 in the article retrieved May 9, 2011
func popCountUint32(x uint32) uint32 {
	x -= (x >> 1) & m1             //put count of each 2 bits into those 2 bits
	x = (x & m2) + ((x >> 2) & m2) //put count of each 4 bits into those 4 bits
	x = (x + (x >> 4)) & m4        //put count of each 8 bits into those 8 bits
	x += x >> 8                    //put count of each 16 bits into their lowest 8 bits
	x += x >> 16                   //put count of each 32 bits into their lowest 8 bits
	//x += x >> 32;  //put count of each 64 bits into their lowest 8 bits
	return x & 0x7f
}

// Count (number of set bits)
func (b *BitSet) Count() uint {
	if b != nil && b.set != nil {
		cnt := uint32(0)
		for _, word := range b.set {
			cnt += popCountUint32(word)
		}
		return uint(cnt)
	}
	return 0
}

// Test the equvalence of two BitSets.
// False if they are of different sizes, otherwise true
// only if all the same bits are set
func (b *BitSet) Equal(c *BitSet) bool {
	if c == nil {
		return false
	}
	if b.length != c.length {
		return false
	}
	for p, v := range b.safeSet() {
		if c.set[p] != v {
			return false
		}
	}
	return true
}

func panicIfNull(b *BitSet) {
	if b == nil {
		panic(BitSetError("BitSet must not be null"))
	}
}

// Difference of base set and other set
// This is the BitSet equivalent of &^ (and not)
func (b *BitSet) Difference(compare *BitSet) (result *BitSet) {
	panicIfNull(b)
	panicIfNull(compare)
	result = b.Clone() // clone b (in case b is bigger than compare)
	szl := compare.wordCount()
	for i, word := range b.safeSet() {
		if uint(i) >= szl {
			break
		}
		result.set[i] = word &^ compare.set[i]
	}
	return
}

// Convenience function: return two bitsets ordered by
// increasing length. Note: neither can be nil
func sortByLength(a *BitSet, b *BitSet) (ap *BitSet, bp *BitSet) {
	if a.length <= b.length {
		ap, bp = a, b
	} else {
		ap, bp = b, a
	}
	return
}

// Intersection of base set and other set
// This is the BitSet equivalent of & (and)
func (b *BitSet) Intersection(compare *BitSet) (result *BitSet) {
	panicIfNull(b)
	panicIfNull(compare)
	b, compare = sortByLength(b, compare)
	result = New(b.length)
	for i, word := range b.safeSet() {
		result.set[i] = word & compare.set[i]
	}
	return
}

// Union of base set and other set
// This is the BitSet equivalent of | (or)
func (b *BitSet) Union(compare *BitSet) (result *BitSet) {
	panicIfNull(b)
	panicIfNull(compare)
	b, compare = sortByLength(b, compare)
	result = compare.Clone()
	szl := compare.wordCount()
	for i, word := range b.safeSet() {
		if uint(i) >= szl {
			break
		}
		result.set[i] = word | compare.set[i]
	}
	return
}

// SymmetricDifference of base set and other set
// This is the BitSet equivalent of ^ (xor)
func (b *BitSet) SymmetricDifference(compare *BitSet) (result *BitSet) {
	panicIfNull(b)
	panicIfNull(compare)
	b, compare = sortByLength(b, compare)
	// compare is bigger, so clone it
	result = compare.Clone()
	szl := b.wordCount()
	for i, word := range b.safeSet() {
		if uint(i) >= szl {
			break
		}
		result.set[i] = word ^ compare.set[i]
	}
	return
}

// Is the length an exact multiple of word sizes?
func (b *BitSet) isEven() bool {
	return (b.length % wordSize) == 0
}

// Clean last word by setting unused bits to 0
func (b *BitSet) cleanLastWord() {
	if !b.isEven() {
		b.set[wordsNeeded(b.length)-1] &= (allBits >> (wordSize - (b.length % wordSize)))
	}
}

// Return the (local) Complement of a biset (up to length bits)
func (b *BitSet) Complement() (result *BitSet) {
	panicIfNull(b)
	result = New(b.length)
	for i, word := range b.safeSet() {
		result.set[i] = ^(word)
	}
	result.cleanLastWord()
	return
}

// Returns true if all bits are set, false otherwise
func (b *BitSet) All() bool {
	panicIfNull(b)
	return b.Count() == b.length
}

// Return true if no bit is set, false otherwise
func (b *BitSet) None() bool {
	panicIfNull(b)
	if b != nil && b.set != nil {
		for _, word := range b.set {
			if word > 0 {
				return false
			}
		}
		return true
	}
	return true
}

// Return true if any bit is set, false otherwise
func (b *BitSet) Any() bool {
	panicIfNull(b)
	return !b.None()
}

// Dump as bits
func (b *BitSet) DumpAsBits() string {
	buffer := bytes.NewBufferString("")
	b.safeSet()
	i := int(wordsNeeded(b.length) - 1)
	for ; i >= 0; i-- {
		fmt.Fprintf(buffer, "%032b.", b.set[i])
	}
	return string(buffer.Bytes())
}
<|endoftext|>


<commit_before>package webircgateway

import (
	"fmt"
	"log"
	"net"
	"net/http"
	"runtime/debug"
	"strings"
	"sync"

	"github.com/igm/sockjs-go/sockjs"
	"github.com/orcaman/concurrent-map"
)

type Channel struct {
	Conn         sockjs.Session
	Client       *Client
	Id           string
	waitForClose chan bool
	ClosedLock   sync.Mutex
	Closed       bool
}

var nextChannelID int

func makeChannel(chanID string, ws sockjs.Session) *Channel {
	client := NewClient()

	originHeader := strings.ToLower(ws.Request().Header.Get("Origin"))
	if !isClientOriginAllowed(originHeader) {
		client.Log(2, "Origin %s not allowed. Closing connection", originHeader)
		ws.Close(0, "Origin not allowed")
		return nil
	}

	client.RemoteAddr = GetRemoteAddressFromRequest(ws.Request()).String()

	clientHostnames, err := net.LookupAddr(client.RemoteAddr)
	if err != nil {
		client.RemoteHostname = client.RemoteAddr
	} else {
		// FQDNs include a . at the end. Strip it out
		potentialHostname := strings.Trim(clientHostnames[0], ".")

		// Must check that the resolved hostname also resolves back to the users IP
		addr, err := net.LookupIP(potentialHostname)
		if err == nil && len(addr) == 1 && addr[0].String() == client.RemoteAddr {
			client.RemoteHostname = potentialHostname
		} else {
			client.RemoteHostname = client.RemoteAddr
		}
	}

	if isRequestSecure(ws.Request()) {
		client.Tags["secure"] = ""
	}

	// This doesn't make sense to have since the remote port may change between requests. Only
	// here for testing purposes for now.
	_, remoteAddrPort, _ := net.SplitHostPort(ws.Request().RemoteAddr)
	client.Tags["remote-port"] = remoteAddrPort

	client.Log(2, "New kiwi channel from %s %s", client.RemoteAddr, client.RemoteHostname)

	channel := &Channel{
		Id:           chanID,
		Client:       client,
		Conn:         ws,
		waitForClose: make(chan bool),
		Closed:       false,
	}

	go channel.listenForSignals()

	return channel
}

func (c *Channel) listenForSignals() {
	for {
		signal, ok := <-c.Client.Signals
		if !ok {
			break
		}
		c.Client.Log(1, "signal:%s %s", signal[0], signal[1])
		if signal[0] == "state" {
			if signal[1] == "connected" {
				c.Conn.Send(fmt.Sprintf(":%s control connected", c.Id))
			} else if signal[1] == "closed" {
				c.Conn.Send(fmt.Sprintf(":%s control closed %s", c.Id, signal[2]))
			}
		}

		if signal[0] == "data" {
			toSend := strings.Trim(signal[1], "\r\n")
			c.Conn.Send(fmt.Sprintf(":%s %s", c.Id, toSend))
		}
	}

	c.ClosedLock.Lock()

	c.Closed = true
	close(c.Client.Recv)
	close(c.waitForClose)

	c.ClosedLock.Unlock()
}

func (c *Channel) handleIncomingLine(line string) {
	c.ClosedLock.Lock()

	if !c.Closed {
		c.Client.Recv <- line
	}

	c.ClosedLock.Unlock()
}

func kiwiircHTTPHandler(router *http.ServeMux) {
	handler := sockjs.NewHandler("/webirc/kiwiirc", sockjs.DefaultOptions, kiwiircHandler)
	router.Handle("/webirc/kiwiirc/", handler)
}

func kiwiircHandler(session sockjs.Session) {
	// Don't let a single users error kill the entire service for everyone
	defer func() {
		if r := recover(); r != nil {
			log.Printf("[ERROR] Recovered from %s\n%s", r, debug.Stack())
		}
	}()

	channels := cmap.New()

	// Read from sockjs
	go func() {
		for {
			msg, err := session.Recv()
			if err == nil && len(msg) > 0 {
				idEnd := strings.Index(msg, " ")
				if idEnd == -1 {
					// msg is in the form of ":chanId"
					chanID := msg[1:]

					_, channelExists := channels.Get(chanID)
					if !channelExists {
						channel := makeChannel(chanID, session)
						if channel == nil {
							continue
						}
						channels.Set(chanID, channel)

						// When the channel closes, remove it from the map again
						go func() {
							<-channel.waitForClose
							channel.Client.Log(2, "Removing channel from connection")
							channels.Remove(chanID)
						}()
					}

					session.Send(":" + chanID)

				} else {
					// msg is in the form of ":chanId data"
					chanID := msg[1:idEnd]
					data := msg[idEnd+1:]

					channel, channelExists := channels.Get(chanID)
					if channelExists {
						c := channel.(*Channel)
						c.handleIncomingLine(data)
					}
				}
			} else if err != nil {
				logOut(1, "kiwi connection closed (%s)", err.Error())
				break
			}
		}

		for channel := range channels.Iter() {
			c := channel.Val.(*Channel)
			c.Closed = true
			c.Client.StartShutdown("client_closed")
		}
	}()
}
<commit_msg>fix gateway on windows<commit_after>package webircgateway

import (
	"fmt"
	"log"
	"net"
	"net/http"
	"runtime/debug"
	"strings"
	"sync"

	"github.com/igm/sockjs-go/sockjs"
	"github.com/orcaman/concurrent-map"
)

type Channel struct {
	Conn         sockjs.Session
	Client       *Client
	Id           string
	waitForClose chan bool
	ClosedLock   sync.Mutex
	Closed       bool
}

var nextChannelID int

func makeChannel(chanID string, ws sockjs.Session) *Channel {
	client := NewClient()

	originHeader := strings.ToLower(ws.Request().Header.Get("Origin"))
	if !isClientOriginAllowed(originHeader) {
		client.Log(2, "Origin %s not allowed. Closing connection", originHeader)
		ws.Close(0, "Origin not allowed")
		return nil
	}

	client.RemoteAddr = GetRemoteAddressFromRequest(ws.Request()).String()

	clientHostnames, err := net.LookupAddr(client.RemoteAddr)
	if err != nil || len(clientHostnames) == 0 {
		client.RemoteHostname = client.RemoteAddr
	} else {
		// FQDNs include a . at the end. Strip it out
		potentialHostname := strings.Trim(clientHostnames[0], ".")

		// Must check that the resolved hostname also resolves back to the users IP
		addr, err := net.LookupIP(potentialHostname)
		if err == nil && len(addr) == 1 && addr[0].String() == client.RemoteAddr {
			client.RemoteHostname = potentialHostname
		} else {
			client.RemoteHostname = client.RemoteAddr
		}
	}

	if isRequestSecure(ws.Request()) {
		client.Tags["secure"] = ""
	}

	// This doesn't make sense to have since the remote port may change between requests. Only
	// here for testing purposes for now.
	_, remoteAddrPort, _ := net.SplitHostPort(ws.Request().RemoteAddr)
	client.Tags["remote-port"] = remoteAddrPort

	client.Log(2, "New kiwi channel from %s %s", client.RemoteAddr, client.RemoteHostname)

	channel := &Channel{
		Id:           chanID,
		Client:       client,
		Conn:         ws,
		waitForClose: make(chan bool),
		Closed:       false,
	}

	go channel.listenForSignals()

	return channel
}

func (c *Channel) listenForSignals() {
	for {
		signal, ok := <-c.Client.Signals
		if !ok {
			break
		}
		c.Client.Log(1, "signal:%s %s", signal[0], signal[1])
		if signal[0] == "state" {
			if signal[1] == "connected" {
				c.Conn.Send(fmt.Sprintf(":%s control connected", c.Id))
			} else if signal[1] == "closed" {
				c.Conn.Send(fmt.Sprintf(":%s control closed %s", c.Id, signal[2]))
			}
		}

		if signal[0] == "data" {
			toSend := strings.Trim(signal[1], "\r\n")
			c.Conn.Send(fmt.Sprintf(":%s %s", c.Id, toSend))
		}
	}

	c.ClosedLock.Lock()

	c.Closed = true
	close(c.Client.Recv)
	close(c.waitForClose)

	c.ClosedLock.Unlock()
}

func (c *Channel) handleIncomingLine(line string) {
	c.ClosedLock.Lock()

	if !c.Closed {
		c.Client.Recv <- line
	}

	c.ClosedLock.Unlock()
}

func kiwiircHTTPHandler(router *http.ServeMux) {
	handler := sockjs.NewHandler("/webirc/kiwiirc", sockjs.DefaultOptions, kiwiircHandler)
	router.Handle("/webirc/kiwiirc/", handler)
}

func kiwiircHandler(session sockjs.Session) {
	// Don't let a single users error kill the entire service for everyone
	defer func() {
		if r := recover(); r != nil {
			log.Printf("[ERROR] Recovered from %s\n%s", r, debug.Stack())
		}
	}()

	channels := cmap.New()

	// Read from sockjs
	go func() {
		for {
			msg, err := session.Recv()
			if err == nil && len(msg) > 0 {
				idEnd := strings.Index(msg, " ")
				if idEnd == -1 {
					// msg is in the form of ":chanId"
					chanID := msg[1:]

					_, channelExists := channels.Get(chanID)
					if !channelExists {
						channel := makeChannel(chanID, session)
						if channel == nil {
							continue
						}
						channels.Set(chanID, channel)

						// When the channel closes, remove it from the map again
						go func() {
							<-channel.waitForClose
							channel.Client.Log(2, "Removing channel from connection")
							channels.Remove(chanID)
						}()
					}

					session.Send(":" + chanID)

				} else {
					// msg is in the form of ":chanId data"
					chanID := msg[1:idEnd]
					data := msg[idEnd+1:]

					channel, channelExists := channels.Get(chanID)
					if channelExists {
						c := channel.(*Channel)
						c.handleIncomingLine(data)
					}
				}
			} else if err != nil {
				logOut(1, "kiwi connection closed (%s)", err.Error())
				break
			}
		}

		for channel := range channels.Iter() {
			c := channel.Val.(*Channel)
			c.Closed = true
			c.Client.StartShutdown("client_closed")
		}
	}()
}
<|endoftext|>