<commit_before>// 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 alertmanager

import (
	"fmt"
	"net/url"
	"path"

	"k8s.io/client-go/pkg/api/resource"
	"k8s.io/client-go/pkg/api/v1"
	"k8s.io/client-go/pkg/apis/apps/v1beta1"
	"k8s.io/client-go/pkg/util/intstr"

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

const (
	governingServiceName = "alertmanager-operated"
	defaultBaseImage     = "quay.io/prometheus/alertmanager"
	defaultVersion       = "v0.5.1"
)

var (
	minReplicas int32 = 1
)

func makeStatefulSet(am *v1alpha1.Alertmanager, old *v1beta1.StatefulSet, config Config) *v1beta1.StatefulSet {
	// TODO(fabxc): is this the right point to inject defaults?
	// Ideally we would do it before storing but that's currently not possible.
	// Potentially an update handler on first insertion.

	if am.Spec.BaseImage == "" {
		am.Spec.BaseImage = defaultBaseImage
	}
	if am.Spec.Version == "" {
		am.Spec.Version = defaultVersion
	}
	if am.Spec.Replicas != nil && *am.Spec.Replicas < minReplicas {
		am.Spec.Replicas = &minReplicas
	}
	if am.Spec.Resources.Requests == nil {
		am.Spec.Resources.Requests = v1.ResourceList{}
	}
	if _, ok := am.Spec.Resources.Requests[v1.ResourceMemory]; !ok {
		am.Spec.Resources.Requests[v1.ResourceMemory] = resource.MustParse("200Mi")
	}

	statefulset := &v1beta1.StatefulSet{
		ObjectMeta: v1.ObjectMeta{
			Name:        prefixedName(am.Name),
			Labels:      am.ObjectMeta.Labels,
			Annotations: am.ObjectMeta.Annotations,
		},
		Spec: makeStatefulSetSpec(am, config),
	}

	if am.Spec.ImagePullSecrets != nil && len(am.Spec.ImagePullSecrets) > 0 {
		statefulset.Spec.Template.Spec.ImagePullSecrets = am.Spec.ImagePullSecrets
	}

	if vc := am.Spec.Storage; vc == nil {
		statefulset.Spec.Template.Spec.Volumes = append(statefulset.Spec.Template.Spec.Volumes, v1.Volume{
			Name: volumeName(am.Name),
			VolumeSource: v1.VolumeSource{
				EmptyDir: &v1.EmptyDirVolumeSource{},
			},
		})
	} else {
		pvc := v1.PersistentVolumeClaim{
			ObjectMeta: v1.ObjectMeta{
				Name: volumeName(am.Name),
			},
			Spec: v1.PersistentVolumeClaimSpec{
				AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce},
				Resources:   vc.Resources,
				Selector:    vc.Selector,
			},
		}
		if len(vc.Class) > 0 {
			pvc.ObjectMeta.Annotations = map[string]string{
				"volume.beta.kubernetes.io/storage-class": vc.Class,
			}
		}
		statefulset.Spec.VolumeClaimTemplates = append(statefulset.Spec.VolumeClaimTemplates, pvc)
	}

	if old != nil {
		statefulset.Annotations = old.Annotations
	}
	return statefulset
}

func makeStatefulSetService(p *v1alpha1.Alertmanager) *v1.Service {
	svc := &v1.Service{
		ObjectMeta: v1.ObjectMeta{
			Name: governingServiceName,
			Labels: map[string]string{
				"operated-alertmanager": "true",
			},
		},
		Spec: v1.ServiceSpec{
			ClusterIP: "None",
			Ports: []v1.ServicePort{
				{
					Name:       "web",
					Port:       9093,
					TargetPort: intstr.FromInt(9093),
					Protocol:   v1.ProtocolTCP,
				},
				{
					Name:       "mesh",
					Port:       6783,
					TargetPort: intstr.FromInt(6783),
					Protocol:   v1.ProtocolTCP,
				},
			},
			Selector: map[string]string{
				"app": "alertmanager",
			},
		},
	}
	return svc
}

func makeStatefulSetSpec(a *v1alpha1.Alertmanager, config Config) v1beta1.StatefulSetSpec {
	image := fmt.Sprintf("%s:%s", a.Spec.BaseImage, a.Spec.Version)

	commands := []string{
		"/bin/alertmanager",
		fmt.Sprintf("-config.file=%s", "/etc/alertmanager/config/alertmanager.yaml"),
		fmt.Sprintf("-web.listen-address=:%d", 9093),
		fmt.Sprintf("-mesh.listen-address=:%d", 6783),
		fmt.Sprintf("-storage.path=%s", "/etc/alertmanager/data"),
	}

	webRoutePrefix := ""
	if a.Spec.ExternalURL != "" {
		commands = append(commands, "-web.external-url="+a.Spec.ExternalURL)
		extUrl, err := url.Parse(a.Spec.ExternalURL)
		if err == nil {
			webRoutePrefix = extUrl.Path
		}
	}

	localReloadURL := &url.URL{
		Scheme: "http",
		Host:   "localhost:9093",
		Path:   path.Clean(webRoutePrefix + "/-/reload"),
	}

	for i := int32(0); i < *a.Spec.Replicas; i++ {
		commands = append(commands, fmt.Sprintf("-mesh.peer=%s-%d.%s.%s.svc", prefixedName(a.Name), i, governingServiceName, a.Namespace))
	}

	terminationGracePeriod := int64(0)
	return v1beta1.StatefulSetSpec{
		ServiceName: governingServiceName,
		Replicas:    a.Spec.Replicas,
		Template: v1.PodTemplateSpec{
			ObjectMeta: v1.ObjectMeta{
				Labels: map[string]string{
					"app":          "alertmanager",
					"alertmanager": a.Name,
				},
			},
			Spec: v1.PodSpec{
				NodeSelector:                  a.Spec.NodeSelector,
				TerminationGracePeriodSeconds: &terminationGracePeriod,
				Containers: []v1.Container{
					{
						Command: commands,
						Name:    "alertmanager",
						Image:   image,
						Ports: []v1.ContainerPort{
							{
								Name:          "web",
								ContainerPort: 9093,
								Protocol:      v1.ProtocolTCP,
							},
							{
								Name:          "mesh",
								ContainerPort: 6783,
								Protocol:      v1.ProtocolTCP,
							},
						},
						VolumeMounts: []v1.VolumeMount{
							{
								Name:      "config-volume",
								MountPath: "/etc/alertmanager/config",
							},
							{
								Name:      volumeName(a.Name),
								MountPath: "/var/alertmanager/data",
								SubPath:   subPathForStorage(a.Spec.Storage),
							},
						},
						ReadinessProbe: &v1.Probe{
							Handler: v1.Handler{
								HTTPGet: &v1.HTTPGetAction{
									Path: path.Clean(webRoutePrefix + "/api/v1/status"),
									Port: intstr.FromString("web"),
								},
							},
							InitialDelaySeconds: 3,
							TimeoutSeconds:      3,
							PeriodSeconds:       5,
							FailureThreshold:    10,
						},
						Resources: a.Spec.Resources,
					}, {
						Name:  "config-reloader",
						Image: config.ConfigReloaderImage,
						Args: []string{
							fmt.Sprintf("-webhook-url=%s", localReloadURL),
							"-volume-dir=/etc/alertmanager/config",
						},
						VolumeMounts: []v1.VolumeMount{
							{
								Name:      "config-volume",
								ReadOnly:  true,
								MountPath: "/etc/alertmanager/config",
							},
						},
						Resources: v1.ResourceRequirements{
							Limits: v1.ResourceList{
								v1.ResourceCPU:    resource.MustParse("5m"),
								v1.ResourceMemory: resource.MustParse("10Mi"),
							},
						},
					},
				},
				Volumes: []v1.Volume{
					{
						Name: "config-volume",
						VolumeSource: v1.VolumeSource{
							Secret: &v1.SecretVolumeSource{
								SecretName: configSecretName(a.Name),
							},
						},
					},
				},
			},
		},
	}
}

func configSecretName(name string) string {
	return prefixedName(name)
}

func volumeName(name string) string {
	return fmt.Sprintf("%s-db", prefixedName(name))
}

func prefixedName(name string) string {
	return fmt.Sprintf("alertmanager-%s", name)
}

func subPathForStorage(s *v1alpha1.StorageSpec) string {
	if s == nil {
		return ""
	}

	return "alertmanager-db"
}
<commit_msg>alertmanager: add liveness probe<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 alertmanager

import (
	"fmt"
	"net/url"
	"path"

	"k8s.io/client-go/pkg/api/resource"
	"k8s.io/client-go/pkg/api/v1"
	"k8s.io/client-go/pkg/apis/apps/v1beta1"
	"k8s.io/client-go/pkg/util/intstr"

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

const (
	governingServiceName = "alertmanager-operated"
	defaultBaseImage     = "quay.io/prometheus/alertmanager"
	defaultVersion       = "v0.5.1"
)

var (
	minReplicas         int32 = 1
	probeTimeoutSeconds int32 = 3
)

func makeStatefulSet(am *v1alpha1.Alertmanager, old *v1beta1.StatefulSet, config Config) *v1beta1.StatefulSet {
	// TODO(fabxc): is this the right point to inject defaults?
	// Ideally we would do it before storing but that's currently not possible.
	// Potentially an update handler on first insertion.

	if am.Spec.BaseImage == "" {
		am.Spec.BaseImage = defaultBaseImage
	}
	if am.Spec.Version == "" {
		am.Spec.Version = defaultVersion
	}
	if am.Spec.Replicas != nil && *am.Spec.Replicas < minReplicas {
		am.Spec.Replicas = &minReplicas
	}
	if am.Spec.Resources.Requests == nil {
		am.Spec.Resources.Requests = v1.ResourceList{}
	}
	if _, ok := am.Spec.Resources.Requests[v1.ResourceMemory]; !ok {
		am.Spec.Resources.Requests[v1.ResourceMemory] = resource.MustParse("200Mi")
	}

	statefulset := &v1beta1.StatefulSet{
		ObjectMeta: v1.ObjectMeta{
			Name:        prefixedName(am.Name),
			Labels:      am.ObjectMeta.Labels,
			Annotations: am.ObjectMeta.Annotations,
		},
		Spec: makeStatefulSetSpec(am, config),
	}

	if am.Spec.ImagePullSecrets != nil && len(am.Spec.ImagePullSecrets) > 0 {
		statefulset.Spec.Template.Spec.ImagePullSecrets = am.Spec.ImagePullSecrets
	}

	if vc := am.Spec.Storage; vc == nil {
		statefulset.Spec.Template.Spec.Volumes = append(statefulset.Spec.Template.Spec.Volumes, v1.Volume{
			Name: volumeName(am.Name),
			VolumeSource: v1.VolumeSource{
				EmptyDir: &v1.EmptyDirVolumeSource{},
			},
		})
	} else {
		pvc := v1.PersistentVolumeClaim{
			ObjectMeta: v1.ObjectMeta{
				Name: volumeName(am.Name),
			},
			Spec: v1.PersistentVolumeClaimSpec{
				AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce},
				Resources:   vc.Resources,
				Selector:    vc.Selector,
			},
		}
		if len(vc.Class) > 0 {
			pvc.ObjectMeta.Annotations = map[string]string{
				"volume.beta.kubernetes.io/storage-class": vc.Class,
			}
		}
		statefulset.Spec.VolumeClaimTemplates = append(statefulset.Spec.VolumeClaimTemplates, pvc)
	}

	if old != nil {
		statefulset.Annotations = old.Annotations
	}
	return statefulset
}

func makeStatefulSetService(p *v1alpha1.Alertmanager) *v1.Service {
	svc := &v1.Service{
		ObjectMeta: v1.ObjectMeta{
			Name: governingServiceName,
			Labels: map[string]string{
				"operated-alertmanager": "true",
			},
		},
		Spec: v1.ServiceSpec{
			ClusterIP: "None",
			Ports: []v1.ServicePort{
				{
					Name:       "web",
					Port:       9093,
					TargetPort: intstr.FromInt(9093),
					Protocol:   v1.ProtocolTCP,
				},
				{
					Name:       "mesh",
					Port:       6783,
					TargetPort: intstr.FromInt(6783),
					Protocol:   v1.ProtocolTCP,
				},
			},
			Selector: map[string]string{
				"app": "alertmanager",
			},
		},
	}
	return svc
}

func makeStatefulSetSpec(a *v1alpha1.Alertmanager, config Config) v1beta1.StatefulSetSpec {
	image := fmt.Sprintf("%s:%s", a.Spec.BaseImage, a.Spec.Version)

	commands := []string{
		"/bin/alertmanager",
		fmt.Sprintf("-config.file=%s", "/etc/alertmanager/config/alertmanager.yaml"),
		fmt.Sprintf("-web.listen-address=:%d", 9093),
		fmt.Sprintf("-mesh.listen-address=:%d", 6783),
		fmt.Sprintf("-storage.path=%s", "/etc/alertmanager/data"),
	}

	webRoutePrefix := ""
	if a.Spec.ExternalURL != "" {
		commands = append(commands, "-web.external-url="+a.Spec.ExternalURL)
		extUrl, err := url.Parse(a.Spec.ExternalURL)
		if err == nil {
			webRoutePrefix = extUrl.Path
		}
	}

	localReloadURL := &url.URL{
		Scheme: "http",
		Host:   "localhost:9093",
		Path:   path.Clean(webRoutePrefix + "/-/reload"),
	}

	probeHandler := v1.Handler{
		HTTPGet: &v1.HTTPGetAction{
			Path: path.Clean(webRoutePrefix + "/api/v1/status"),
			Port: intstr.FromString("web"),
		},
	}

	for i := int32(0); i < *a.Spec.Replicas; i++ {
		commands = append(commands, fmt.Sprintf("-mesh.peer=%s-%d.%s.%s.svc", prefixedName(a.Name), i, governingServiceName, a.Namespace))
	}

	terminationGracePeriod := int64(0)
	return v1beta1.StatefulSetSpec{
		ServiceName: governingServiceName,
		Replicas:    a.Spec.Replicas,
		Template: v1.PodTemplateSpec{
			ObjectMeta: v1.ObjectMeta{
				Labels: map[string]string{
					"app":          "alertmanager",
					"alertmanager": a.Name,
				},
			},
			Spec: v1.PodSpec{
				NodeSelector:                  a.Spec.NodeSelector,
				TerminationGracePeriodSeconds: &terminationGracePeriod,
				Containers: []v1.Container{
					{
						Command: commands,
						Name:    "alertmanager",
						Image:   image,
						Ports: []v1.ContainerPort{
							{
								Name:          "web",
								ContainerPort: 9093,
								Protocol:      v1.ProtocolTCP,
							},
							{
								Name:          "mesh",
								ContainerPort: 6783,
								Protocol:      v1.ProtocolTCP,
							},
						},
						VolumeMounts: []v1.VolumeMount{
							{
								Name:      "config-volume",
								MountPath: "/etc/alertmanager/config",
							},
							{
								Name:      volumeName(a.Name),
								MountPath: "/var/alertmanager/data",
								SubPath:   subPathForStorage(a.Spec.Storage),
							},
						},
						LivenessProbe: &v1.Probe{
							Handler:          probeHandler,
							TimeoutSeconds:   probeTimeoutSeconds,
							FailureThreshold: 10,
						},
						ReadinessProbe: &v1.Probe{
							Handler:             probeHandler,
							InitialDelaySeconds: 3,
							TimeoutSeconds:      3,
							PeriodSeconds:       5,
							FailureThreshold:    10,
						},
						Resources: a.Spec.Resources,
					}, {
						Name:  "config-reloader",
						Image: config.ConfigReloaderImage,
						Args: []string{
							fmt.Sprintf("-webhook-url=%s", localReloadURL),
							"-volume-dir=/etc/alertmanager/config",
						},
						VolumeMounts: []v1.VolumeMount{
							{
								Name:      "config-volume",
								ReadOnly:  true,
								MountPath: "/etc/alertmanager/config",
							},
						},
						Resources: v1.ResourceRequirements{
							Limits: v1.ResourceList{
								v1.ResourceCPU:    resource.MustParse("5m"),
								v1.ResourceMemory: resource.MustParse("10Mi"),
							},
						},
					},
				},
				Volumes: []v1.Volume{
					{
						Name: "config-volume",
						VolumeSource: v1.VolumeSource{
							Secret: &v1.SecretVolumeSource{
								SecretName: configSecretName(a.Name),
							},
						},
					},
				},
			},
		},
	}
}

func configSecretName(name string) string {
	return prefixedName(name)
}

func volumeName(name string) string {
	return fmt.Sprintf("%s-db", prefixedName(name))
}

func prefixedName(name string) string {
	return fmt.Sprintf("alertmanager-%s", name)
}

func subPathForStorage(s *v1alpha1.StorageSpec) string {
	if s == nil {
		return ""
	}

	return "alertmanager-db"
}
<|endoftext|>


<commit_before><commit_msg>Stubbed out methods in dpn_queue.go<commit_after><|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"strings"
	"time"
)

var openPrefixes = []string{
	"/git",
	"/buildByToken",
	"/cli",
	"/jnlpJars",
	"/subversion",
	"/whoAmI",
}

const version = "1.1"
const planio_url = "https://recras.plan.io/users/current.json"

var authCache = map[string]time.Time{}

func main() {
	jenkins_address := os.Getenv("JENKINS_URL")
	listen_address := os.Getenv("LISTEN_ADDRESS")

	if listen_address == "" {
		listen_address = "[::]:8080"
	}
	if jenkins_address == "" {
		log.Fatalln("Use environment variables JENKINS_URL and LISTEN_ADDRESS (default \"[::]:8080\")")
	}

	remote, err := url.Parse(jenkins_address)
	if err != nil {
		log.Panic(err)
	}

	proxy := httputil.NewSingleHostReverseProxy(remote)
	http.HandleFunc("/", handler(proxy))

	err = http.ListenAndServe(listen_address, nil)
	if err != nil {
		log.Panic(err)
	}
}

func isOpenPrefix(requestURI string) bool {
	for _, prefix := range openPrefixes {
		if strings.HasPrefix(requestURI, prefix) {
			return true
		}
	}
	return false
}

func isCached(authorization string) bool {
	const cacheTime = time.Duration(5) * time.Minute

	if t, ok := authCache[authorization]; ok {
		if time.Now().Before(t.Add(cacheTime)) {
			return true
		}
		log.Print("cache expired:", authorization)
		delete(authCache, authorization)
	}
	return false
}

func addToCache(authorization string) {
	authCache[authorization] = time.Now()
	log.Print("added to cache:", authorization)
}

func authenticateWithBackend(req *http.Request) (bool, error) {
	if isCached(req.Header["Authorization"][0]) {
		return true, nil
	}

	var r *http.Request
	var err error
	var resp *http.Response

	r, err = http.NewRequest("GET", planio_url, nil)
	if err != nil {
		return false, err
	}
	r.Header["Authorization"] = req.Header["Authorization"]

	client := http.Client{}
	resp, err = client.Do(r)
	if err != nil {
		return false, err
	}

	resp.Body.Close()
	if resp.StatusCode == 200 {
		addToCache(req.Header["Authorization"][0])
		return true, nil
	}
	return false, nil
}

func handler(fw *httputil.ReverseProxy) func(http.ResponseWriter, *http.Request) {
	return func(wr http.ResponseWriter, req *http.Request) {
		wr.Header()["X-Powered-By"] = []string{"jenkins-authentication-proxy/" + version}
		if isOpenPrefix(req.RequestURI) {
			fw.ServeHTTP(wr, req)
			return
		}

		if authed, err := authenticateWithBackend(req); err != nil {
			wr.WriteHeader(http.StatusInternalServerError)
			fmt.Fprint(wr, "error", err)
			log.Print(err)
		} else if authed {
			fw.ServeHTTP(wr, req)
		} else {
			wr.Header()["Www-Authenticate"] = []string{"Basic realm=\"Jenkins\""}
			wr.WriteHeader(http.StatusUnauthorized)
		}
	}
}
<commit_msg>Add hello message<commit_after>package main

import (
	"fmt"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"strings"
	"time"
)

var openPrefixes = []string{
	"/git",
	"/buildByToken",
	"/cli",
	"/jnlpJars",
	"/subversion",
	"/whoAmI",
}

const version = "1.1"
const planio_url = "https://recras.plan.io/users/current.json"

var authCache = map[string]time.Time{}

func main() {
	jenkins_address := os.Getenv("JENKINS_URL")
	listen_address := os.Getenv("LISTEN_ADDRESS")

	if listen_address == "" {
		listen_address = "[::]:8080"
	}
	if jenkins_address == "" {
		log.Fatalln("Use environment variables JENKINS_URL and LISTEN_ADDRESS (default \"[::]:8080\")")
	}

	remote, err := url.Parse(jenkins_address)
	if err != nil {
		log.Panic(err)
	}

	proxy := httputil.NewSingleHostReverseProxy(remote)
	http.HandleFunc("/", handler(proxy))

	log.Println("jenkins-authentication-proxy", version, "starting")
	log.Println("Authentication endpoint:", planio_url)
	err = http.ListenAndServe(listen_address, nil)
	if err != nil {
		log.Panic(err)
	}
}

func isOpenPrefix(requestURI string) bool {
	for _, prefix := range openPrefixes {
		if strings.HasPrefix(requestURI, prefix) {
			return true
		}
	}
	return false
}

func isCached(authorization string) bool {
	const cacheTime = time.Duration(5) * time.Minute

	if t, ok := authCache[authorization]; ok {
		if time.Now().Before(t.Add(cacheTime)) {
			return true
		}
		log.Print("cache expired:", authorization)
		delete(authCache, authorization)
	}
	return false
}

func addToCache(authorization string) {
	authCache[authorization] = time.Now()
	log.Print("added to cache:", authorization)
}

func authenticateWithBackend(req *http.Request) (bool, error) {
	if isCached(req.Header["Authorization"][0]) {
		return true, nil
	}

	var r *http.Request
	var err error
	var resp *http.Response

	r, err = http.NewRequest("GET", planio_url, nil)
	if err != nil {
		return false, err
	}
	r.Header["Authorization"] = req.Header["Authorization"]

	client := http.Client{}
	resp, err = client.Do(r)
	if err != nil {
		return false, err
	}

	resp.Body.Close()
	if resp.StatusCode == 200 {
		addToCache(req.Header["Authorization"][0])
		return true, nil
	}
	return false, nil
}

func handler(fw *httputil.ReverseProxy) func(http.ResponseWriter, *http.Request) {
	return func(wr http.ResponseWriter, req *http.Request) {
		wr.Header()["X-Powered-By"] = []string{"jenkins-authentication-proxy/" + version}
		if isOpenPrefix(req.RequestURI) {
			fw.ServeHTTP(wr, req)
			return
		}

		if authed, err := authenticateWithBackend(req); err != nil {
			wr.WriteHeader(http.StatusInternalServerError)
			fmt.Fprint(wr, "error", err)
			log.Print(err)
		} else if authed {
			fw.ServeHTTP(wr, req)
		} else {
			wr.Header()["Www-Authenticate"] = []string{"Basic realm=\"Jenkins\""}
			wr.WriteHeader(http.StatusUnauthorized)
		}
	}
}
<|endoftext|>


<commit_before>/*
 *    Copyright (C) 2014-2017 Christian Muehlhaeuser
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as published
 *    by the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Authors:
 *      Christian Muehlhaeuser <muesli@gmail.com>
 */

package hellobee

import (
	"github.com/muesli/beehive/bees"
)

// HelloBeeFactory is a factory for HelloBees.
type HelloBeeFactory struct {
	bees.BeeFactory
}

// New returns a new Bee instance configured with the supplied options.
func (factory *HelloBeeFactory) New(name, description string, options bees.BeeOptions) bees.BeeInterface {
	bee := HelloBee{
		Bee: bees.NewBee(name, factory.Name(), description, options),
	}
	bee.ReloadOptions(options)

	return &bee
}

// Name returns the name of this Bee.
func (factory *HelloBeeFactory) Name() string {
	return "hellobee"
}

// Description returns the description of this Bee.
func (factory *HelloBeeFactory) Description() string {
	return "A 'Hello World' module for beehive"
}

func init() {
	f := HelloBeeFactory{}
	bees.RegisterFactory(&f)
}
<commit_msg>Fixed HelloBeeFactory<commit_after>/*
 *    Copyright (C) 2014-2017 Christian Muehlhaeuser
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as published
 *    by the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Authors:
 *      Christian Muehlhaeuser <muesli@gmail.com>
 */

package hellobee

import (
	"github.com/muesli/beehive/bees"
)

// HelloBeeFactory is a factory for HelloBees.
type HelloBeeFactory struct {
	bees.BeeFactory
}

// New returns a new Bee instance configured with the supplied options.
func (factory *HelloBeeFactory) New(name, description string, options bees.BeeOptions) bees.BeeInterface {
	bee := HelloBee{
		Bee: bees.NewBee(name, factory.Name(), description, options),
	}
	bee.ReloadOptions(options)

	return &bee
}

// ID returns the ID of this Bee.
func (factory *HelloBeeFactory) ID() string {
	return "hellobee"
}

// Name returns the name of this Bee.
func (factory *HelloBeeFactory) Name() string {
	return "Hello"
}

// Description returns the description of this Bee.
func (factory *HelloBeeFactory) Description() string {
	return "A 'Hello World' module for beehive"
}

func init() {
	f := HelloBeeFactory{}
	bees.RegisterFactory(&f)
}
<|endoftext|>


<commit_before>package stages

import (
	"bytes"
	"errors"
	"reflect"
	"strings"
	"text/template"
	"time"

	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
	"github.com/mitchellh/mapstructure"
	"github.com/prometheus/common/model"
)

// Config Errors
const (
	ErrEmptyTemplateStageConfig = "template stage config cannot be empty"
	ErrTemplateSourceRequired   = "template source value is required"
)

var (
	functionMap = template.FuncMap{
		"ToLower":    strings.ToLower,
		"ToUpper":    strings.ToUpper,
		"Replace":    strings.Replace,
		"Trim":       strings.Trim,
		"TrimLeft":   strings.TrimLeft,
		"TrimRight":  strings.TrimRight,
		"TrimPrefix": strings.TrimPrefix,
		"TrimSuffix": strings.TrimSuffix,
		"TrimSpace":  strings.TrimSpace,
	}
)

// TemplateConfig configures template value extraction
type TemplateConfig struct {
	Source   string `mapstructure:"source"`
	Template string `mapstructure:"template"`
}

// validateTemplateConfig validates the templateStage config
func validateTemplateConfig(cfg *TemplateConfig) (*template.Template, error) {
	if cfg == nil {
		return nil, errors.New(ErrEmptyTemplateStageConfig)
	}
	if cfg.Source == "" {
		return nil, errors.New(ErrTemplateSourceRequired)
	}

	return template.New("pipeline_template").Funcs(functionMap).Parse(cfg.Template)
}

// newTemplateStage creates a new templateStage
func newTemplateStage(logger log.Logger, config interface{}) (*templateStage, error) {
	cfg := &TemplateConfig{}
	err := mapstructure.Decode(config, cfg)
	if err != nil {
		return nil, err
	}
	t, err := validateTemplateConfig(cfg)
	if err != nil {
		return nil, err
	}

	return &templateStage{
		cfgs:     cfg,
		logger:   logger,
		template: t,
	}, nil
}

// templateStage will mutate the incoming entry and set it from extracted data
type templateStage struct {
	cfgs     *TemplateConfig
	logger   log.Logger
	template *template.Template
}

// Process implements Stage
func (o *templateStage) Process(labels model.LabelSet, extracted map[string]interface{}, t *time.Time, entry *string) {
	if o.cfgs == nil {
		return
	}
	td := make(map[string]interface{})
	for k, v := range extracted {
		s, err := getString(v)
		if err != nil {
			if Debug {
				level.Debug(o.logger).Log("msg", "extracted template could not be converted to a string", "err", err, "type", reflect.TypeOf(v))
			}
			continue
		}
		td[k] = s
		if k == o.cfgs.Source {
			td["Value"] = s
		}
	}

	buf := &bytes.Buffer{}
	err := o.template.Execute(buf, td)
	if err != nil {
		if Debug {
			level.Debug(o.logger).Log("msg", "failed to execute template on extracted value", "err", err)
		}
		return
	}
	st := buf.String()
	// If the template evaluates to an empty string, remove the key from the map
	if st == "" {
		delete(extracted, o.cfgs.Source)
	} else {
		extracted[o.cfgs.Source] = st
	}

}

// Name implements Stage
func (o *templateStage) Name() string {
	return StageTypeTemplate
}
<commit_msg>Add Entry variable to template (#2105)<commit_after>package stages

import (
	"bytes"
	"errors"
	"reflect"
	"strings"
	"text/template"
	"time"

	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
	"github.com/mitchellh/mapstructure"
	"github.com/prometheus/common/model"
)

// Config Errors
const (
	ErrEmptyTemplateStageConfig = "template stage config cannot be empty"
	ErrTemplateSourceRequired   = "template source value is required"
)

var (
	functionMap = template.FuncMap{
		"ToLower":    strings.ToLower,
		"ToUpper":    strings.ToUpper,
		"Replace":    strings.Replace,
		"Trim":       strings.Trim,
		"TrimLeft":   strings.TrimLeft,
		"TrimRight":  strings.TrimRight,
		"TrimPrefix": strings.TrimPrefix,
		"TrimSuffix": strings.TrimSuffix,
		"TrimSpace":  strings.TrimSpace,
	}
)

// TemplateConfig configures template value extraction
type TemplateConfig struct {
	Source   string `mapstructure:"source"`
	Template string `mapstructure:"template"`
}

// validateTemplateConfig validates the templateStage config
func validateTemplateConfig(cfg *TemplateConfig) (*template.Template, error) {
	if cfg == nil {
		return nil, errors.New(ErrEmptyTemplateStageConfig)
	}
	if cfg.Source == "" {
		return nil, errors.New(ErrTemplateSourceRequired)
	}

	return template.New("pipeline_template").Funcs(functionMap).Parse(cfg.Template)
}

// newTemplateStage creates a new templateStage
func newTemplateStage(logger log.Logger, config interface{}) (*templateStage, error) {
	cfg := &TemplateConfig{}
	err := mapstructure.Decode(config, cfg)
	if err != nil {
		return nil, err
	}
	t, err := validateTemplateConfig(cfg)
	if err != nil {
		return nil, err
	}

	return &templateStage{
		cfgs:     cfg,
		logger:   logger,
		template: t,
	}, nil
}

// templateStage will mutate the incoming entry and set it from extracted data
type templateStage struct {
	cfgs     *TemplateConfig
	logger   log.Logger
	template *template.Template
}

// Process implements Stage
func (o *templateStage) Process(labels model.LabelSet, extracted map[string]interface{}, t *time.Time, entry *string) {
	if o.cfgs == nil {
		return
	}
	td := make(map[string]interface{})
	for k, v := range extracted {
		s, err := getString(v)
		if err != nil {
			if Debug {
				level.Debug(o.logger).Log("msg", "extracted template could not be converted to a string", "err", err, "type", reflect.TypeOf(v))
			}
			continue
		}
		td[k] = s
		if k == o.cfgs.Source {
			td["Value"] = s
		}
	}
	td["Entry"] = *entry

	buf := &bytes.Buffer{}
	err := o.template.Execute(buf, td)
	if err != nil {
		if Debug {
			level.Debug(o.logger).Log("msg", "failed to execute template on extracted value", "err", err)
		}
		return
	}
	st := buf.String()
	// If the template evaluates to an empty string, remove the key from the map
	if st == "" {
		delete(extracted, o.cfgs.Source)
	} else {
		extracted[o.cfgs.Source] = st
	}

}

// Name implements Stage
func (o *templateStage) Name() string {
	return StageTypeTemplate
}
<|endoftext|>


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

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

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

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

package problem

import "regexp"

// re is a shortcut around regexp.MustCompile
func re(s string) *regexp.Regexp {
	return regexp.MustCompile(s)
}

// vmProblems are VM related problems
var vmProblems = map[string]match{
	"SERVICE_NOT_FOUND": {
		Regexp: re(`Could not find finalized endpoint being pointed to by`),
		Advice: "Please make sure the service you are looking for is deployed or is in the correct namespace.",
		Issues: []int{4599},
	},
	"HYPERKIT_NO_IP": {
		Regexp: re(`IP address never found in dhcp leases file Temporary Error: Could not find an IP address for`),
		Advice: "Install the latest minikube hyperkit driver, and run 'minikube delete'",
		URL:    "https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#hyperkit-driver",
		Issues: []int{1926, 4206},
	},
	"VBOX_NOT_FOUND": {
		Regexp: re(`VBoxManage not found. Make sure VirtualBox is installed and VBoxManage is in the path`),
		Advice: "Install VirtualBox, ensure that VBoxManage is executable and in path, or select an alternative value for --vm-driver",
		URL:    "https://www.virtualbox.org/wiki/Downloads",
		Issues: []int{3784, 3776},
	},
	"VBOX_VTX_DISABLED": {
		Regexp: re(`This computer doesn't have VT-X/AMD-v enabled`),
		Advice: "In some environments, this message is incorrect. Try 'minikube start --no-vtx-check'",
		Issues: []int{3900},
	},
	"VBOX_VERR_VMX_NO_VMX": {
		Regexp: re(`VT-x is not available.*VERR_VMX_NO_VMX`),
		Advice: "Please check your BIOS, and ensure that you are running without HyperV or other nested virtualization that may interfere",
		Issues: []int{1994},
	},
	"VBOX_BLOCKED": {
		Regexp: re(`NS_ERROR_FAILURE.*0x80004005`),
		Advice: "Reinstall VirtualBox and verify that it is not blocked: System Preferences -> Security & Privacy -> General -> Some system software was blocked from loading",
		Issues: []int{4107},
		GOOS:   "darwin",
	},
	"VBOX_DRV_NOT_LOADED": {
		Regexp: re(`The vboxdrv kernel module is not loaded`),
		Advice: "Run 'sudo modprobe vboxdrv' and reinstall VirtualBox if it fails.",
		Issues: []int{4043},
	},
	"VBOX_DEVICE_MISSING": {
		Regexp: re(`/dev/vboxdrv does not exist`),
		Advice: "Run 'sudo modprobe vboxdrv' and reinstall VirtualBox if it fails.",
		Issues: []int{3974},
	},
	"VBOX_HARDENING": {
		Regexp: re(`terminated unexpectedly.*VBoxHardening`),
		Advice: "Disable real-time anti-virus software, reboot, and reinstall VirtualBox if the problem continues.",
		Issues: []int{3859, 3910},
		URL:    "https://forums.virtualbox.org/viewtopic.php?f=25&t=82106",
		GOOS:   "windows",
	},
	"VBOX_HOST_ADAPTER": {
		Regexp: re(`The host-only adapter we just created is not visible`),
		Advice: "Reboot to complete VirtualBox installation, and verify that VirtualBox is not blocked by your system",
		Issues: []int{3614, 4222},
		URL:    "https://stackoverflow.com/questions/52277019/how-to-fix-vm-issue-with-minikube-start",
	},
	"VBOX_KERNEL_MODULE_NOT_LOADED": {
		Regexp: re(`The vboxdrv kernel module is not loaded`),
		Advice: "Run 'sudo modprobe vboxdrv' and reinstall VirtualBox if it fails.",
		Issues: []int{4043},
	},
	"KVM2_NOT_FOUND": {
		Regexp: re(`Driver "kvm2" not found. Do you have the plugin binary .* accessible in your PATH`),
		Advice: "Please install the minikube kvm2 VM driver, or select an alternative --vm-driver",
		URL:    "https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#kvm2-driver",
	},
	"KVM2_RESTART_NO_IP": {
		Regexp: re(`Error starting stopped host: Machine didn't return an IP after 120 seconds`),
		Advice: "The KVM driver is unable to resurrect this old VM. Please run `minikube delete` to delete it and try again.",
		Issues: []int{3901, 3434},
	},
	"KVM2_START_NO_IP": {
		Regexp: re(`Error in driver during machine creation: Machine didn't return an IP after 120 seconds`),
		Advice: "Install the latest kvm2 driver and run 'virt-host-validate'",
		URL:    "https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#kvm2-driver",
		Issues: []int{4249, 3566},
	},
	"KVM2_NETWORK_DEFINE_XML": {
		Regexp: re(`not supported by the connection driver: virNetworkDefineXML`),
		Advice: "Rebuild libvirt with virt-network support",
		URL:    "https://forums.gentoo.org/viewtopic-t-981692-start-0.html",
		Issues: []int{4195},
	},
	"KVM2_QEMU_MONITOR": {
		Regexp: re(`qemu unexpectedly closed the monitor`),
		Advice: "Upgrade to QEMU v3.1.0+, run 'virt-host-validate', or ensure that you are not running in a nested VM environment.",
		Issues: []int{4277},
	},
	"KVM_UNAVAILABLE": {
		Regexp: re(`invalid argument: could not find capabilities for domaintype=kvm`),
		Advice: "Your host does not support KVM virtualization. Ensure that qemu-kvm is installed, and run 'virt-host-validate' to debug the problem",
		URL:    "http://mikko.repolainen.fi/documents/virtualization-with-kvm",
		Issues: []int{2991},
	},
	"DRIVER_CRASHED": {
		Regexp: re(`Error attempting to get plugin server address for RPC`),
		Advice: "The VM driver exited with an error, and may be corrupt. Run 'minikube start' with --alsologtostderr -v=8 to see the error",
		URL:    "https://github.com/kubernetes/minikube/blob/master/docs/drivers.md",
	},
	"DRIVER_EXITED": {
		Regexp: re(`Unable to start VM: create: creating: exit status 1`),
		Advice: "Re-run 'minikube start' with --alsologtostderr -v=8 to see the VM driver error message",
		URL:    "https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#troubleshooting",
	},
	"VM_BOOT_FAILED_HYPERV_ENABLED": {
		Regexp: re(`VirtualBox won't boot a 64bits VM when Hyper-V is activated`),
		Advice: "Disable Hyper-V when you want to run VirtualBox to boot the VM",
		Issues: []int{4051},
	},
	"HYPERV_NO_VSWITCH": {
		Regexp: re(`no External vswitch found. A valid vswitch must be available for this command to run.`),
		Advice: "Configure an external network switch following the official documentation, then add `--hyperv-virtual-switch=<switch-name>` to `minikube start`",
		URL:    "https://docs.docker.com/machine/drivers/hyper-v/",
	},
	"HOST_CIDR_CONFLICT": {
		Regexp: re(`host-only cidr conflicts with the network address of a host interface`),
		Advice: "Specify an alternate --host-only-cidr value, such as 172.16.0.1/24",
		Issues: []int{3594},
	},
	"OOM_KILL_SSH": {
		Regexp: re(`Process exited with status 137 from signal KILL`),
		Advice: "Disable dynamic memory in your VM manager, or pass in a larger --memory value",
		Issues: []int{1766},
	},
	"OOM_KILL_SCP": {
		Regexp: re(`An existing connection was forcibly closed by the remote host`),
		Advice: "Disable dynamic memory in your VM manager, or pass in a larger --memory value",
		Issues: []int{1766},
	},
}

// proxyDoc is the URL to proxy documentation
const proxyDoc = "https://github.com/kubernetes/minikube/blob/master/docs/http_proxy.md"

// netProblems are network related problems.
var netProblems = map[string]match{
	"GCR_UNAVAILABLE": {
		Regexp: re(`gcr.io.*443: connect: invalid argument`),
		Advice: "minikube is unable to access the Google Container Registry. You may need to configure it to use a HTTP proxy.",
		URL:    proxyDoc,
		Issues: []int{3860},
	},
	"DOWNLOAD_RESET_BY_PEER": {
		Regexp: re(`Error downloading .*connection reset by peer`),
		Advice: "A firewall is likely blocking minikube from reaching the internet. You may need to configure minikube to use a proxy.",
		URL:    proxyDoc,
		Issues: []int{3909},
	},
	"DOWNLOAD_IO_TIMEOUT": {
		Regexp: re(`Error downloading .*timeout`),
		Advice: "A firewall is likely blocking minikube from reaching the internet. You may need to configure minikube to use a proxy.",
		URL:    proxyDoc,
		Issues: []int{3846},
	},
	"DOWNLOAD_TLS_OVERSIZED": {
		Regexp: re(`tls: oversized record received with length`),
		Advice: "A firewall is interfering with minikube's ability to make outgoing HTTPS requests. You may need to change the value of the HTTPS_PROXY environment variable.",
		URL:    proxyDoc,
		Issues: []int{3857, 3759, 4252},
	},
	"ISO_DOWNLOAD_FAILED": {
		Regexp: re(`iso: failed to download`),
		Advice: "A firewall is likely blocking minikube from reaching the internet. You may need to configure minikube to use a proxy.",
		URL:    proxyDoc,
		Issues: []int{3922},
	},
	"PULL_TIMEOUT_EXCEEDED": {
		Regexp: re(`failed to pull image k8s.gcr.io.*Client.Timeout exceeded while awaiting headers`),
		Advice: "A firewall is blocking Docker within the minikube VM from reaching the internet. You may need to configure it to use a proxy.",
		URL:    proxyDoc,
		Issues: []int{3898},
	},
	"SSH_AUTH_FAILURE": {
		Regexp: re(`ssh: handshake failed: ssh: unable to authenticate.*, no supported methods remain`),
		Advice: "Your host is failing to route packets to the minikube VM. If you have VPN software, try turning it off or configuring it so that it does not re-route traffic to the VM IP. If not, check your VM environment routing options.",
		Issues: []int{3930},
	},
	"SSH_TCP_FAILURE": {
		Regexp: re(`dial tcp .*:22: connectex: A connection attempt failed because the connected party did not properly respond`),
		Advice: "Your host is failing to route packets to the minikube VM. If you have VPN software, try turning it off or configuring it so that it does not re-route traffic to the VM IP. If not, check your VM environment routing options.",
		Issues: []int{3388},
	},
	"INVALID_PROXY_HOSTNAME": {
		Regexp: re(`dial tcp: lookup.*: no such host`),
		Advice: "Verify that your HTTP_PROXY and HTTPS_PROXY environment variables are set correctly.",
		URL:    proxyDoc,
	},
}

// deployProblems are Kubernetes deployment problems.
var deployProblems = map[string]match{
	"DOCKER_UNAVAILABLE": {
		Regexp: re(`Error configuring auth on host: OS type not recognized`),
		Advice: "Docker inside the VM is unavailable. Try running 'minikube delete' to reset the VM.",
		Issues: []int{3952},
	},
	"INVALID_KUBERNETES_VERSION": {
		Regexp: re(`No Major.Minor.Patch elements found`),
		Advice: "Specify --kubernetes-version in v<major>.<minor.<build> form. example: 'v1.1.14'",
	},
	"KUBERNETES_VERSION_MISSING_V": {
		Regexp: re(`strconv.ParseUint: parsing "": invalid syntax`),
		Advice: "Check that your --kubernetes-version has a leading 'v'. For example: 'v1.1.14'",
	},
	"APISERVER_TIMEOUT": {
		Regexp: re(`wait: waiting for component=kube-apiserver: timed out waiting for the condition`),
		Advice: "Run 'minikube delete'. If the problem persists, check your proxy or firewall configuration",
		Issues: []int{4202, 3836, 4221},
	},
}

// osProblems are operating-system specific issues
var osProblems = map[string]match{
	"NON_C_DRIVE": {
		Regexp: re(`.iso: The system cannot find the path specified.`),
		Advice: "Run minikube from the C: drive.",
		Issues: []int{1574},
	},
	"SYSTEMCTL_EXIT_1": {
		Regexp: re(`Failed to enable container runtime: .*sudo systemctl start docker: exit status 1`),
		Advice: "If using the none driver, ensure that systemctl is installed",
		URL:    "https://github.com/kubernetes/minikube/blob/master/docs/vmdriver-none.md",
		Issues: []int{2704},
	},
}

// stateProblems are issues relating to local state
var stateProblems = map[string]match{
	"MACHINE_DOES_NOT_EXST": {
		Regexp: re(`Error getting state for host: machine does not exist`),
		Advice: "Run 'minikube delete' to delete the stale VM",
		Issues: []int{3864},
	},
	"IP_NOT_FOUND": {
		Regexp: re(`Error getting ssh host name for driver: IP not found`),
		Advice: "The minikube VM is offline. Please run 'minikube start' to start it again.",
		Issues: []int{3849, 3648},
	},
}
<commit_msg>Add kvm connection error problem message<commit_after>/*
Copyright 2019 The Kubernetes Authors All rights reserved.

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

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

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

package problem

import "regexp"

// re is a shortcut around regexp.MustCompile
func re(s string) *regexp.Regexp {
	return regexp.MustCompile(s)
}

// vmProblems are VM related problems
var vmProblems = map[string]match{
	"SERVICE_NOT_FOUND": {
		Regexp: re(`Could not find finalized endpoint being pointed to by`),
		Advice: "Please make sure the service you are looking for is deployed or is in the correct namespace.",
		Issues: []int{4599},
	},
	"HYPERKIT_NO_IP": {
		Regexp: re(`IP address never found in dhcp leases file Temporary Error: Could not find an IP address for`),
		Advice: "Install the latest minikube hyperkit driver, and run 'minikube delete'",
		URL:    "https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#hyperkit-driver",
		Issues: []int{1926, 4206},
	},
	"VBOX_NOT_FOUND": {
		Regexp: re(`VBoxManage not found. Make sure VirtualBox is installed and VBoxManage is in the path`),
		Advice: "Install VirtualBox, ensure that VBoxManage is executable and in path, or select an alternative value for --vm-driver",
		URL:    "https://www.virtualbox.org/wiki/Downloads",
		Issues: []int{3784, 3776},
	},
	"VBOX_VTX_DISABLED": {
		Regexp: re(`This computer doesn't have VT-X/AMD-v enabled`),
		Advice: "In some environments, this message is incorrect. Try 'minikube start --no-vtx-check'",
		Issues: []int{3900},
	},
	"VBOX_VERR_VMX_NO_VMX": {
		Regexp: re(`VT-x is not available.*VERR_VMX_NO_VMX`),
		Advice: "Please check your BIOS, and ensure that you are running without HyperV or other nested virtualization that may interfere",
		Issues: []int{1994},
	},
	"VBOX_BLOCKED": {
		Regexp: re(`NS_ERROR_FAILURE.*0x80004005`),
		Advice: "Reinstall VirtualBox and verify that it is not blocked: System Preferences -> Security & Privacy -> General -> Some system software was blocked from loading",
		Issues: []int{4107},
		GOOS:   "darwin",
	},
	"VBOX_DRV_NOT_LOADED": {
		Regexp: re(`The vboxdrv kernel module is not loaded`),
		Advice: "Run 'sudo modprobe vboxdrv' and reinstall VirtualBox if it fails.",
		Issues: []int{4043},
	},
	"VBOX_DEVICE_MISSING": {
		Regexp: re(`/dev/vboxdrv does not exist`),
		Advice: "Run 'sudo modprobe vboxdrv' and reinstall VirtualBox if it fails.",
		Issues: []int{3974},
	},
	"VBOX_HARDENING": {
		Regexp: re(`terminated unexpectedly.*VBoxHardening`),
		Advice: "Disable real-time anti-virus software, reboot, and reinstall VirtualBox if the problem continues.",
		Issues: []int{3859, 3910},
		URL:    "https://forums.virtualbox.org/viewtopic.php?f=25&t=82106",
		GOOS:   "windows",
	},
	"VBOX_HOST_ADAPTER": {
		Regexp: re(`The host-only adapter we just created is not visible`),
		Advice: "Reboot to complete VirtualBox installation, and verify that VirtualBox is not blocked by your system",
		Issues: []int{3614, 4222},
		URL:    "https://stackoverflow.com/questions/52277019/how-to-fix-vm-issue-with-minikube-start",
	},
	"VBOX_KERNEL_MODULE_NOT_LOADED": {
		Regexp: re(`The vboxdrv kernel module is not loaded`),
		Advice: "Run 'sudo modprobe vboxdrv' and reinstall VirtualBox if it fails.",
		Issues: []int{4043},
	},
	"KVM2_NOT_FOUND": {
		Regexp: re(`Driver "kvm2" not found. Do you have the plugin binary .* accessible in your PATH`),
		Advice: "Please install the minikube kvm2 VM driver, or select an alternative --vm-driver",
		URL:    "https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#kvm2-driver",
	},
	"KVM2_RESTART_NO_IP": {
		Regexp: re(`Error starting stopped host: Machine didn't return an IP after 120 seconds`),
		Advice: "The KVM driver is unable to resurrect this old VM. Please run `minikube delete` to delete it and try again.",
		Issues: []int{3901, 3434},
	},
	"KVM2_START_NO_IP": {
		Regexp: re(`Error in driver during machine creation: Machine didn't return an IP after 120 seconds`),
		Advice: "Install the latest kvm2 driver and run 'virt-host-validate'",
		URL:    "https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#kvm2-driver",
		Issues: []int{4249, 3566},
	},
	"KVM2_NETWORK_DEFINE_XML": {
		Regexp: re(`not supported by the connection driver: virNetworkDefineXML`),
		Advice: "Rebuild libvirt with virt-network support",
		URL:    "https://forums.gentoo.org/viewtopic-t-981692-start-0.html",
		Issues: []int{4195},
	},
	"KVM2_QEMU_MONITOR": {
		Regexp: re(`qemu unexpectedly closed the monitor`),
		Advice: "Upgrade to QEMU v3.1.0+, run 'virt-host-validate', or ensure that you are not running in a nested VM environment.",
		Issues: []int{4277},
	},
	"KVM_UNAVAILABLE": {
		Regexp: re(`invalid argument: could not find capabilities for domaintype=kvm`),
		Advice: "Your host does not support KVM virtualization. Ensure that qemu-kvm is installed, and run 'virt-host-validate' to debug the problem",
		URL:    "http://mikko.repolainen.fi/documents/virtualization-with-kvm",
		Issues: []int{2991},
	},
	"KVM_CONNECTION_ERROR": {
		Regexp: re(`error connecting to libvirt socket`),
		Advice: "Have you set up libvirt correctly?",
		URL:    "https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#kvm2-driver",
	},
	"DRIVER_CRASHED": {
		Regexp: re(`Error attempting to get plugin server address for RPC`),
		Advice: "The VM driver exited with an error, and may be corrupt. Run 'minikube start' with --alsologtostderr -v=8 to see the error",
		URL:    "https://github.com/kubernetes/minikube/blob/master/docs/drivers.md",
	},
	"DRIVER_EXITED": {
		Regexp: re(`Unable to start VM: create: creating: exit status 1`),
		Advice: "Re-run 'minikube start' with --alsologtostderr -v=8 to see the VM driver error message",
		URL:    "https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#troubleshooting",
	},
	"VM_BOOT_FAILED_HYPERV_ENABLED": {
		Regexp: re(`VirtualBox won't boot a 64bits VM when Hyper-V is activated`),
		Advice: "Disable Hyper-V when you want to run VirtualBox to boot the VM",
		Issues: []int{4051},
	},
	"HYPERV_NO_VSWITCH": {
		Regexp: re(`no External vswitch found. A valid vswitch must be available for this command to run.`),
		Advice: "Configure an external network switch following the official documentation, then add `--hyperv-virtual-switch=<switch-name>` to `minikube start`",
		URL:    "https://docs.docker.com/machine/drivers/hyper-v/",
	},
	"HOST_CIDR_CONFLICT": {
		Regexp: re(`host-only cidr conflicts with the network address of a host interface`),
		Advice: "Specify an alternate --host-only-cidr value, such as 172.16.0.1/24",
		Issues: []int{3594},
	},
	"OOM_KILL_SSH": {
		Regexp: re(`Process exited with status 137 from signal KILL`),
		Advice: "Disable dynamic memory in your VM manager, or pass in a larger --memory value",
		Issues: []int{1766},
	},
	"OOM_KILL_SCP": {
		Regexp: re(`An existing connection was forcibly closed by the remote host`),
		Advice: "Disable dynamic memory in your VM manager, or pass in a larger --memory value",
		Issues: []int{1766},
	},
}

// proxyDoc is the URL to proxy documentation
const proxyDoc = "https://github.com/kubernetes/minikube/blob/master/docs/http_proxy.md"

// netProblems are network related problems.
var netProblems = map[string]match{
	"GCR_UNAVAILABLE": {
		Regexp: re(`gcr.io.*443: connect: invalid argument`),
		Advice: "minikube is unable to access the Google Container Registry. You may need to configure it to use a HTTP proxy.",
		URL:    proxyDoc,
		Issues: []int{3860},
	},
	"DOWNLOAD_RESET_BY_PEER": {
		Regexp: re(`Error downloading .*connection reset by peer`),
		Advice: "A firewall is likely blocking minikube from reaching the internet. You may need to configure minikube to use a proxy.",
		URL:    proxyDoc,
		Issues: []int{3909},
	},
	"DOWNLOAD_IO_TIMEOUT": {
		Regexp: re(`Error downloading .*timeout`),
		Advice: "A firewall is likely blocking minikube from reaching the internet. You may need to configure minikube to use a proxy.",
		URL:    proxyDoc,
		Issues: []int{3846},
	},
	"DOWNLOAD_TLS_OVERSIZED": {
		Regexp: re(`tls: oversized record received with length`),
		Advice: "A firewall is interfering with minikube's ability to make outgoing HTTPS requests. You may need to change the value of the HTTPS_PROXY environment variable.",
		URL:    proxyDoc,
		Issues: []int{3857, 3759, 4252},
	},
	"ISO_DOWNLOAD_FAILED": {
		Regexp: re(`iso: failed to download`),
		Advice: "A firewall is likely blocking minikube from reaching the internet. You may need to configure minikube to use a proxy.",
		URL:    proxyDoc,
		Issues: []int{3922},
	},
	"PULL_TIMEOUT_EXCEEDED": {
		Regexp: re(`failed to pull image k8s.gcr.io.*Client.Timeout exceeded while awaiting headers`),
		Advice: "A firewall is blocking Docker within the minikube VM from reaching the internet. You may need to configure it to use a proxy.",
		URL:    proxyDoc,
		Issues: []int{3898},
	},
	"SSH_AUTH_FAILURE": {
		Regexp: re(`ssh: handshake failed: ssh: unable to authenticate.*, no supported methods remain`),
		Advice: "Your host is failing to route packets to the minikube VM. If you have VPN software, try turning it off or configuring it so that it does not re-route traffic to the VM IP. If not, check your VM environment routing options.",
		Issues: []int{3930},
	},
	"SSH_TCP_FAILURE": {
		Regexp: re(`dial tcp .*:22: connectex: A connection attempt failed because the connected party did not properly respond`),
		Advice: "Your host is failing to route packets to the minikube VM. If you have VPN software, try turning it off or configuring it so that it does not re-route traffic to the VM IP. If not, check your VM environment routing options.",
		Issues: []int{3388},
	},
	"INVALID_PROXY_HOSTNAME": {
		Regexp: re(`dial tcp: lookup.*: no such host`),
		Advice: "Verify that your HTTP_PROXY and HTTPS_PROXY environment variables are set correctly.",
		URL:    proxyDoc,
	},
}

// deployProblems are Kubernetes deployment problems.
var deployProblems = map[string]match{
	"DOCKER_UNAVAILABLE": {
		Regexp: re(`Error configuring auth on host: OS type not recognized`),
		Advice: "Docker inside the VM is unavailable. Try running 'minikube delete' to reset the VM.",
		Issues: []int{3952},
	},
	"INVALID_KUBERNETES_VERSION": {
		Regexp: re(`No Major.Minor.Patch elements found`),
		Advice: "Specify --kubernetes-version in v<major>.<minor.<build> form. example: 'v1.1.14'",
	},
	"KUBERNETES_VERSION_MISSING_V": {
		Regexp: re(`strconv.ParseUint: parsing "": invalid syntax`),
		Advice: "Check that your --kubernetes-version has a leading 'v'. For example: 'v1.1.14'",
	},
	"APISERVER_TIMEOUT": {
		Regexp: re(`wait: waiting for component=kube-apiserver: timed out waiting for the condition`),
		Advice: "Run 'minikube delete'. If the problem persists, check your proxy or firewall configuration",
		Issues: []int{4202, 3836, 4221},
	},
}

// osProblems are operating-system specific issues
var osProblems = map[string]match{
	"NON_C_DRIVE": {
		Regexp: re(`.iso: The system cannot find the path specified.`),
		Advice: "Run minikube from the C: drive.",
		Issues: []int{1574},
	},
	"SYSTEMCTL_EXIT_1": {
		Regexp: re(`Failed to enable container runtime: .*sudo systemctl start docker: exit status 1`),
		Advice: "If using the none driver, ensure that systemctl is installed",
		URL:    "https://github.com/kubernetes/minikube/blob/master/docs/vmdriver-none.md",
		Issues: []int{2704},
	},
}

// stateProblems are issues relating to local state
var stateProblems = map[string]match{
	"MACHINE_DOES_NOT_EXST": {
		Regexp: re(`Error getting state for host: machine does not exist`),
		Advice: "Run 'minikube delete' to delete the stale VM",
		Issues: []int{3864},
	},
	"IP_NOT_FOUND": {
		Regexp: re(`Error getting ssh host name for driver: IP not found`),
		Advice: "The minikube VM is offline. Please run 'minikube start' to start it again.",
		Issues: []int{3849, 3648},
	},
}
<|endoftext|>


<commit_before>package prompting

import (
	"errors"
	"fmt"
)

// streamPrompter implements Prompter on top of a Prompting_HostServer stream.
type streamPrompter struct {
	// allowPrompts indicates whether or not the client allows prompts.
	allowPrompts bool
	// stream is the underlying Prompting_HostServer stream.
	stream Prompting_HostServer
}

// sendReceive performs a send/receive cycle by sending a HostResponse and
// receiving a HostRequest.
func (p *streamPrompter) sendReceive(response *HostResponse) (*HostRequest, error) {
	// Send the request.
	if err := p.stream.Send(response); err != nil {
		return nil, fmt.Errorf("unable to send response: %w", err)
	}

	// Determine the expected request mode.
	mode := hostRequestModeMessageResponse
	if response.IsPrompt {
		mode = hostRequestModePromptResponse
	}

	// Receive the response.
	if request, err := p.stream.Recv(); err != nil {
		return nil, fmt.Errorf("unable to receive request: %w", err)
	} else if err = request.ensureValid(mode); err != nil {
		return nil, fmt.Errorf("invalid request received: %w", err)
	} else {
		return request, nil
	}
}

// Message implements the Message method of Prompter.
func (p *streamPrompter) Message(message string) error {
	_, err := p.sendReceive(&HostResponse{Message: message})
	return err
}

// Prompt implements the Prompt method of Prompter.
func (p *streamPrompter) Prompt(prompt string) (string, error) {
	// Check whether or not prompts are supported by this client.
	if !p.allowPrompts {
		return "", errors.New("prompter only supports messaging")
	}

	// Perform the exchange.
	if response, err := p.sendReceive(&HostResponse{IsPrompt: true, Message: prompt}); err != nil {
		return "", err
	} else {
		return response.Response, nil
	}
}
<commit_msg>Modified streamPrompter to track errors.<commit_after>package prompting

import (
	"errors"
	"fmt"
)

// streamPrompter implements Prompter on top of a Prompting_HostServer stream.
type streamPrompter struct {
	// allowPrompts indicates whether or not the client allows prompts.
	allowPrompts bool
	// stream is the underlying Prompting_HostServer stream.
	stream Prompting_HostServer
	// errored indicates whether or not the stream has encountered an error.
	errored bool
}

// sendReceive performs a send/receive cycle by sending a HostResponse and
// receiving a HostRequest.
func (p *streamPrompter) sendReceive(response *HostResponse) (*HostRequest, error) {
	// Send the request.
	if err := p.stream.Send(response); err != nil {
		return nil, fmt.Errorf("unable to send response: %w", err)
	}

	// Determine the expected request mode.
	mode := hostRequestModeMessageResponse
	if response.IsPrompt {
		mode = hostRequestModePromptResponse
	}

	// Receive the response.
	if request, err := p.stream.Recv(); err != nil {
		return nil, fmt.Errorf("unable to receive request: %w", err)
	} else if err = request.ensureValid(mode); err != nil {
		return nil, fmt.Errorf("invalid request received: %w", err)
	} else {
		return request, nil
	}
}

// Message implements the Message method of Prompter.
func (p *streamPrompter) Message(message string) error {
	// Check if a previous transmission error has occurred.
	if p.errored {
		return errors.New("prompter encountered previous error")
	}

	// Otherwise perform the messaging operation.
	if _, err := p.sendReceive(&HostResponse{Message: message}); err != nil {
		p.errored = true
		return err
	}

	// Success.
	return nil
}

// Prompt implements the Prompt method of Prompter.
func (p *streamPrompter) Prompt(prompt string) (string, error) {
	// Check if a previous transmission error has occurred.
	if p.errored {
		return "", errors.New("prompter encountered previous error")
	}

	// Check whether or not prompts are supported by this client.
	if !p.allowPrompts {
		return "", errors.New("prompter only supports messaging")
	}

	// Perform the exchange.
	response, err := p.sendReceive(&HostResponse{IsPrompt: true, Message: prompt})
	if err != nil {
		p.errored = true
		return "", err
	}

	// Success.
	return response.Response, nil
}
<|endoftext|>


<commit_before>// Copyright 2021 the u-root 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 spidev

import (
	"encoding/binary"
	"errors"
	"os"
	"reflect"
	"runtime"
	"testing"
	"unsafe"

	"golang.org/x/sys/unix"
)

// mockSpidev simulates the ioctls for spidev.
type mockSpidev struct {
	// forceErrno when set will always return the given error from syscall.
	forceErrno unix.Errno

	mode        Mode
	bitsPerWord uint8
	speedHz     uint32
	transfers   []iocTransfer
}

func (s *mockSpidev) syscall(trap, a1, a2 uintptr, a3 unsafe.Pointer) (r1, r2 uintptr, err unix.Errno) {
	if s.forceErrno != 0 {
		return 0, 0, s.forceErrno
	}

	if trap != unix.SYS_IOCTL {
		return 0, 0, unix.EINVAL
	}
	if a1 < 0 {
		return 0, 0, unix.EINVAL
	}

	switch a2 {
	case iocRdBitsPerWord:
		*(*uint8)(a3) = uint8(s.bitsPerWord)
	case iocWrBitsPerWord:
		s.bitsPerWord = *(*uint8)(a3)
	case iocRdMaxSpeedHz:
		*(*uint32)(a3) = uint32(s.speedHz)
	case iocWrMaxSpeedHz:
		s.speedHz = *(*uint32)(a3)
	case iocRdMode32:
		*(*uint32)(a3) = uint32(s.mode)
	case iocWrMode32:
		s.mode = Mode(*(*uint32)(a3))
	default:
		if uint32(a2&^sizeMask) != iocMessage(0) {
			return 0, 0, unix.EINVAL
		}

		// Parse multiple transfer structs.
		size := int((a2 & sizeMask) >> sizeShift)
		if size%binary.Size(iocTransfer{}) != 0 {
			return 0, 0, unix.EINVAL
		}
		s.transfers = make([]iocTransfer, size/binary.Size(iocTransfer{}))

		// Re-create the slice from the array.
		defer runtime.KeepAlive(a3)
		sh := &reflect.SliceHeader{
			Data: uintptr(a3),
			Len:  len(s.transfers),
			Cap:  len(s.transfers),
		}
		transfers := *(*[]iocTransfer)(unsafe.Pointer(sh))

		// Copy to another slice since the GC will clean it up once the
		// references disappear.
		copy(s.transfers, transfers)

		// Replace all the non-zero address with 0xdeadbeef because the
		// pointer addresses might change during the test.
		for i := range s.transfers {
			t := &s.transfers[i]
			if t.txBuf != 0 {
				t.txBuf = 0xdeadbeef
			}
			if t.rxBuf != 0 {
				t.rxBuf = 0xdeadbeef
			}
		}
	}

	return 0, 0, 0
}

// TestOpenError tests when Open returns an error like file does not exist.
func TestOpenError(t *testing.T) {
	if _, err := Open("/dev/blahblahblahblah"); !os.IsNotExist(err) {
		t.Fatalf(`Open("/dev/blahblahblahblah got %v; want %v`, err, os.ErrNotExist)
	}
}

// TestGetters tests the functions which return values like Mode, SpeedHz, ...
func TestGetters(t *testing.T) {
	tmpFile, err := os.CreateTemp("", "")
	if err != nil {
		t.Fatalf("Could not create temporary file: %v", err)
	}
	defer os.Remove(tmpFile.Name())

	s, err := Open(tmpFile.Name())
	if err != nil {
		t.Fatalf("Could not open spidev: %v", err)
	}
	defer s.Close()

	m := &mockSpidev{
		// You wouldn't use these values in practice, but it is good
		// for a unit test.
		mode:        0x1234,
		bitsPerWord: 10,
		speedHz:     12345,
	}
	s.syscall = m.syscall

	// Test syscall with and without error.
	for _, tt := range []struct {
		name       string
		forceErrno unix.Errno
		wantErr    error
	}{
		{"", 0, nil},
		{"WithErrno", unix.EAGAIN, unix.EAGAIN},
	} {
		m.forceErrno = tt.forceErrno

		t.Run("Mode"+tt.name, func(t *testing.T) {
			m, err := s.Mode()
			if !errors.Is(err, tt.wantErr) {
				t.Errorf("Mode() got error %q; want error %q", err, tt.wantErr)
			}
			if err != nil {
				return
			}
			want := Mode(0x1234)
			if m != want {
				t.Errorf("Mode() = %#v; want %#v", m, want)
			}
		})

		t.Run("BitsPerWord"+tt.name, func(t *testing.T) {
			bpw, err := s.BitsPerWord()
			if !errors.Is(err, tt.wantErr) {
				t.Errorf("BitsPerWord() got error %q; want error %q", err, tt.wantErr)
			}
			if err != nil {
				return
			}
			want := uint8(10)
			if bpw != want {
				t.Errorf("BitsPerWord() = %d; want %d", bpw, want)
			}
		})

		t.Run("SpeedHz"+tt.name, func(t *testing.T) {
			hz, err := s.SpeedHz()
			if !errors.Is(err, tt.wantErr) {
				t.Errorf("SpeedHz() got error %q; want error %q", err, tt.wantErr)
			}
			if err != nil {
				return
			}
			want := uint32(12345)
			if hz != want {
				t.Errorf("SpeedHz() = %d; want %d", hz, want)
			}
		})
	}
}

// TestSetters tests the functions which set values like SetMode, SetSpeedHz, ...
func TestSetters(t *testing.T) {
	tmpFile, err := os.CreateTemp("", "")
	if err != nil {
		t.Fatalf("Could not create temporary file: %v", err)
	}
	defer os.Remove(tmpFile.Name())

	s, err := Open(tmpFile.Name())
	if err != nil {
		t.Fatalf("Could not open spidev: %v", err)
	}
	defer s.Close()

	m := &mockSpidev{}
	s.syscall = m.syscall

	// Test syscall with and without error.
	for _, tt := range []struct {
		name       string
		forceErrno unix.Errno
		wantErr    error
	}{
		{"", 0, nil},
		{"WithErrno", unix.EAGAIN, unix.EAGAIN},
	} {
		m.forceErrno = tt.forceErrno

		t.Run("SetMode"+tt.name, func(t *testing.T) {
			if err := s.SetMode(0x12345); !errors.Is(err, tt.wantErr) {
				t.Errorf("SetMode() got error %q; want error %q", err, tt.wantErr)
			}
			if err != nil {
				return
			}
			const want = Mode(0x12345)
			if m.mode != want {
				t.Errorf("SetMode() = %#v; want %#v", m.mode, want)
			}
		})

		t.Run("SetBitsPerWord"+tt.name, func(t *testing.T) {
			if err := s.SetBitsPerWord(20); !errors.Is(err, tt.wantErr) {
				t.Errorf("SetBitsPerWord() got error %q; want error %q", err, tt.wantErr)
			}
			if err != nil {
				return
			}
			const want = 20
			if m.bitsPerWord != want {
				t.Errorf("SetBitsPerWord() = %d; want %d", m.bitsPerWord, want)
			}
		})

		t.Run("SetSpeedHz"+tt.name, func(t *testing.T) {
			if err := s.SetSpeedHz(12345); !errors.Is(err, tt.wantErr) {
				t.Errorf("SetSpeedHz() got error %q; want error %q", err, tt.wantErr)
			}
			if err != nil {
				return
			}
			const want = 12345
			if m.speedHz != want {
				t.Errorf("SetSpeedHz() = %d; want %d", m.speedHz, want)
			}
		})
	}
}

// TestTransfer tests multiple scenarios involving the Transfer method.
func TestTransfer(t *testing.T) {
	// To avoid OOMing the CI, we set the maxTransferSize to a smaller
	// value temporarily for this test.
	defer func(x int) { maxTransferSize = x }(maxTransferSize)
	maxTransferSize = 0x100000

	for _, tt := range []struct {
		name          string
		transfers     []Transfer
		forceErrno    unix.Errno
		wantTransfers []iocTransfer
		wantErr       error
	}{
		{
			name: "ErrTxOverflow",
			transfers: []Transfer{
				{
					Tx: make([]uint8, maxTransferSize+1),
				},
			},
			wantErr: ErrTxOverflow{
				TxLen: maxTransferSize + 1,
				TxMax: maxTransferSize,
			},
		},
		{
			name: "ErrRxOverflow",
			transfers: []Transfer{
				{
					Rx: make([]uint8, maxTransferSize+1),
				},
			},
			wantErr: ErrRxOverflow{
				RxLen: maxTransferSize + 1,
				RxMax: maxTransferSize,
			},
		},
		{
			name: "ErrBufferMismatch",
			transfers: []Transfer{
				{
					Tx: make([]uint8, 10),
					Rx: make([]uint8, 20),
				},
			},
			wantErr: ErrBufferMismatch{
				TxLen: 10,
				RxLen: 20,
			},
		},
		{
			name:       "Errno",
			forceErrno: unix.EAGAIN,
			transfers: []Transfer{
				{
					Tx: make([]uint8, 10),
					Rx: make([]uint8, 10),
				},
			},
			wantErr: unix.EAGAIN,
		},
		{
			name: "TxZero",
			transfers: []Transfer{
				{
					Rx: make([]uint8, 10),
				},
			},
			wantTransfers: []iocTransfer{
				{
					rxBuf:  0xdeadbeef,
					length: 10,
				},
			},
		},
		{
			name: "RxZero",
			transfers: []Transfer{
				{
					Tx: make([]uint8, 10),
				},
			},
			wantTransfers: []iocTransfer{
				{
					txBuf:  0xdeadbeef,
					length: 10,
				},
			},
		},
		{
			name: "OneTransfer",
			transfers: []Transfer{
				{
					Tx:             []uint8{1, 2, 3},
					Rx:             []uint8{0, 0, 0},
					SpeedHz:        0x12345678,
					DelayUSecs:     0x1234,
					BitsPerWord:    0x8,
					CSChange:       true,
					TxNBits:        24,
					RxNBits:        24,
					WordDelayUSecs: 0x10,
				},
			},
			wantTransfers: []iocTransfer{
				{
					txBuf:          0xdeadbeef,
					rxBuf:          0xdeadbeef,
					length:         3,
					speedHz:        0x12345678,
					delayUSecs:     0x1234,
					bitsPerWord:    0x8,
					csChange:       1,
					txNBits:        24,
					rxNBits:        24,
					wordDelayUSecs: 0x10,
				},
			},
		},
		{
			name: "TwoTransfers",
			transfers: []Transfer{
				{
					Tx: []uint8{1, 2, 3},
					Rx: []uint8{0, 0, 0},
				},
				{
					Tx: []uint8{4, 5, 6, 7},
				},
			},
			wantTransfers: []iocTransfer{
				{
					txBuf:  0xdeadbeef,
					rxBuf:  0xdeadbeef,
					length: 3,
				},
				{
					txBuf:  0xdeadbeef,
					length: 4,
				},
			},
		},
	} {
		t.Run(tt.name, func(t *testing.T) {
			tmpFile, err := os.CreateTemp("", "")
			if err != nil {
				t.Fatalf("Could not create temporary file: %v", err)
			}
			defer os.Remove(tmpFile.Name())

			s, err := Open(tmpFile.Name())
			if err != nil {
				t.Fatalf("Could not open spidev: %v", err)
			}
			defer s.Close()

			m := &mockSpidev{
				forceErrno: tt.forceErrno,
			}
			s.syscall = m.syscall

			gotErr := s.Transfer(tt.transfers)
			if !errors.Is(gotErr, tt.wantErr) {
				t.Errorf("Got Transfer err %q; want %q", gotErr, tt.wantErr)
			}
			if !reflect.DeepEqual(m.transfers, tt.wantTransfers) {
				t.Errorf("Got Transfers %#v; want %#v", m.transfers, tt.wantTransfers)
			}
		})
	}
}
<commit_msg>pkg/spidev/spidev_linux_test.go: fix invalid usage of reflect.SliceHeader<commit_after>// Copyright 2021 the u-root 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 spidev

import (
	"encoding/binary"
	"errors"
	"os"
	"reflect"
	"runtime"
	"testing"
	"unsafe"

	"golang.org/x/sys/unix"
)

// mockSpidev simulates the ioctls for spidev.
type mockSpidev struct {
	// forceErrno when set will always return the given error from syscall.
	forceErrno unix.Errno

	mode        Mode
	bitsPerWord uint8
	speedHz     uint32
	transfers   []iocTransfer
}

func (s *mockSpidev) syscall(trap, a1, a2 uintptr, a3 unsafe.Pointer) (r1, r2 uintptr, err unix.Errno) {
	if s.forceErrno != 0 {
		return 0, 0, s.forceErrno
	}

	if trap != unix.SYS_IOCTL {
		return 0, 0, unix.EINVAL
	}
	if a1 < 0 {
		return 0, 0, unix.EINVAL
	}

	switch a2 {
	case iocRdBitsPerWord:
		*(*uint8)(a3) = uint8(s.bitsPerWord)
	case iocWrBitsPerWord:
		s.bitsPerWord = *(*uint8)(a3)
	case iocRdMaxSpeedHz:
		*(*uint32)(a3) = uint32(s.speedHz)
	case iocWrMaxSpeedHz:
		s.speedHz = *(*uint32)(a3)
	case iocRdMode32:
		*(*uint32)(a3) = uint32(s.mode)
	case iocWrMode32:
		s.mode = Mode(*(*uint32)(a3))
	default:
		if uint32(a2&^sizeMask) != iocMessage(0) {
			return 0, 0, unix.EINVAL
		}

		// Parse multiple transfer structs.
		size := int((a2 & sizeMask) >> sizeShift)
		if size%binary.Size(iocTransfer{}) != 0 {
			return 0, 0, unix.EINVAL
		}
		s.transfers = make([]iocTransfer, size/binary.Size(iocTransfer{}))

		// Re-create the slice from the array.
		transfers := make([]iocTransfer, 0, 0)
		sh := (*reflect.SliceHeader)(unsafe.Pointer(&transfers))
		sh.Data = uintptr(a3)
		sh.Len = len(s.transfers)
		sh.Cap = len(s.transfers)
		// Make sure the original string s is not freed up until this point.
		runtime.KeepAlive(a3)

		// Copy to another slice since the GC will clean it up once the
		// references disappear.
		copy(s.transfers, transfers)

		// Replace all the non-zero address with 0xdeadbeef because the
		// pointer addresses might change during the test.
		for i := range s.transfers {
			t := &s.transfers[i]
			if t.txBuf != 0 {
				t.txBuf = 0xdeadbeef
			}
			if t.rxBuf != 0 {
				t.rxBuf = 0xdeadbeef
			}
		}
	}

	return 0, 0, 0
}

// TestOpenError tests when Open returns an error like file does not exist.
func TestOpenError(t *testing.T) {
	if _, err := Open("/dev/blahblahblahblah"); !os.IsNotExist(err) {
		t.Fatalf(`Open("/dev/blahblahblahblah got %v; want %v`, err, os.ErrNotExist)
	}
}

// TestGetters tests the functions which return values like Mode, SpeedHz, ...
func TestGetters(t *testing.T) {
	tmpFile, err := os.CreateTemp("", "")
	if err != nil {
		t.Fatalf("Could not create temporary file: %v", err)
	}
	defer os.Remove(tmpFile.Name())

	s, err := Open(tmpFile.Name())
	if err != nil {
		t.Fatalf("Could not open spidev: %v", err)
	}
	defer s.Close()

	m := &mockSpidev{
		// You wouldn't use these values in practice, but it is good
		// for a unit test.
		mode:        0x1234,
		bitsPerWord: 10,
		speedHz:     12345,
	}
	s.syscall = m.syscall

	// Test syscall with and without error.
	for _, tt := range []struct {
		name       string
		forceErrno unix.Errno
		wantErr    error
	}{
		{"", 0, nil},
		{"WithErrno", unix.EAGAIN, unix.EAGAIN},
	} {
		m.forceErrno = tt.forceErrno

		t.Run("Mode"+tt.name, func(t *testing.T) {
			m, err := s.Mode()
			if !errors.Is(err, tt.wantErr) {
				t.Errorf("Mode() got error %q; want error %q", err, tt.wantErr)
			}
			if err != nil {
				return
			}
			want := Mode(0x1234)
			if m != want {
				t.Errorf("Mode() = %#v; want %#v", m, want)
			}
		})

		t.Run("BitsPerWord"+tt.name, func(t *testing.T) {
			bpw, err := s.BitsPerWord()
			if !errors.Is(err, tt.wantErr) {
				t.Errorf("BitsPerWord() got error %q; want error %q", err, tt.wantErr)
			}
			if err != nil {
				return
			}
			want := uint8(10)
			if bpw != want {
				t.Errorf("BitsPerWord() = %d; want %d", bpw, want)
			}
		})

		t.Run("SpeedHz"+tt.name, func(t *testing.T) {
			hz, err := s.SpeedHz()
			if !errors.Is(err, tt.wantErr) {
				t.Errorf("SpeedHz() got error %q; want error %q", err, tt.wantErr)
			}
			if err != nil {
				return
			}
			want := uint32(12345)
			if hz != want {
				t.Errorf("SpeedHz() = %d; want %d", hz, want)
			}
		})
	}
}

// TestSetters tests the functions which set values like SetMode, SetSpeedHz, ...
func TestSetters(t *testing.T) {
	tmpFile, err := os.CreateTemp("", "")
	if err != nil {
		t.Fatalf("Could not create temporary file: %v", err)
	}
	defer os.Remove(tmpFile.Name())

	s, err := Open(tmpFile.Name())
	if err != nil {
		t.Fatalf("Could not open spidev: %v", err)
	}
	defer s.Close()

	m := &mockSpidev{}
	s.syscall = m.syscall

	// Test syscall with and without error.
	for _, tt := range []struct {
		name       string
		forceErrno unix.Errno
		wantErr    error
	}{
		{"", 0, nil},
		{"WithErrno", unix.EAGAIN, unix.EAGAIN},
	} {
		m.forceErrno = tt.forceErrno

		t.Run("SetMode"+tt.name, func(t *testing.T) {
			if err := s.SetMode(0x12345); !errors.Is(err, tt.wantErr) {
				t.Errorf("SetMode() got error %q; want error %q", err, tt.wantErr)
			}
			if err != nil {
				return
			}
			const want = Mode(0x12345)
			if m.mode != want {
				t.Errorf("SetMode() = %#v; want %#v", m.mode, want)
			}
		})

		t.Run("SetBitsPerWord"+tt.name, func(t *testing.T) {
			if err := s.SetBitsPerWord(20); !errors.Is(err, tt.wantErr) {
				t.Errorf("SetBitsPerWord() got error %q; want error %q", err, tt.wantErr)
			}
			if err != nil {
				return
			}
			const want = 20
			if m.bitsPerWord != want {
				t.Errorf("SetBitsPerWord() = %d; want %d", m.bitsPerWord, want)
			}
		})

		t.Run("SetSpeedHz"+tt.name, func(t *testing.T) {
			if err := s.SetSpeedHz(12345); !errors.Is(err, tt.wantErr) {
				t.Errorf("SetSpeedHz() got error %q; want error %q", err, tt.wantErr)
			}
			if err != nil {
				return
			}
			const want = 12345
			if m.speedHz != want {
				t.Errorf("SetSpeedHz() = %d; want %d", m.speedHz, want)
			}
		})
	}
}

// TestTransfer tests multiple scenarios involving the Transfer method.
func TestTransfer(t *testing.T) {
	// To avoid OOMing the CI, we set the maxTransferSize to a smaller
	// value temporarily for this test.
	defer func(x int) { maxTransferSize = x }(maxTransferSize)
	maxTransferSize = 0x100000

	for _, tt := range []struct {
		name          string
		transfers     []Transfer
		forceErrno    unix.Errno
		wantTransfers []iocTransfer
		wantErr       error
	}{
		{
			name: "ErrTxOverflow",
			transfers: []Transfer{
				{
					Tx: make([]uint8, maxTransferSize+1),
				},
			},
			wantErr: ErrTxOverflow{
				TxLen: maxTransferSize + 1,
				TxMax: maxTransferSize,
			},
		},
		{
			name: "ErrRxOverflow",
			transfers: []Transfer{
				{
					Rx: make([]uint8, maxTransferSize+1),
				},
			},
			wantErr: ErrRxOverflow{
				RxLen: maxTransferSize + 1,
				RxMax: maxTransferSize,
			},
		},
		{
			name: "ErrBufferMismatch",
			transfers: []Transfer{
				{
					Tx: make([]uint8, 10),
					Rx: make([]uint8, 20),
				},
			},
			wantErr: ErrBufferMismatch{
				TxLen: 10,
				RxLen: 20,
			},
		},
		{
			name:       "Errno",
			forceErrno: unix.EAGAIN,
			transfers: []Transfer{
				{
					Tx: make([]uint8, 10),
					Rx: make([]uint8, 10),
				},
			},
			wantErr: unix.EAGAIN,
		},
		{
			name: "TxZero",
			transfers: []Transfer{
				{
					Rx: make([]uint8, 10),
				},
			},
			wantTransfers: []iocTransfer{
				{
					rxBuf:  0xdeadbeef,
					length: 10,
				},
			},
		},
		{
			name: "RxZero",
			transfers: []Transfer{
				{
					Tx: make([]uint8, 10),
				},
			},
			wantTransfers: []iocTransfer{
				{
					txBuf:  0xdeadbeef,
					length: 10,
				},
			},
		},
		{
			name: "OneTransfer",
			transfers: []Transfer{
				{
					Tx:             []uint8{1, 2, 3},
					Rx:             []uint8{0, 0, 0},
					SpeedHz:        0x12345678,
					DelayUSecs:     0x1234,
					BitsPerWord:    0x8,
					CSChange:       true,
					TxNBits:        24,
					RxNBits:        24,
					WordDelayUSecs: 0x10,
				},
			},
			wantTransfers: []iocTransfer{
				{
					txBuf:          0xdeadbeef,
					rxBuf:          0xdeadbeef,
					length:         3,
					speedHz:        0x12345678,
					delayUSecs:     0x1234,
					bitsPerWord:    0x8,
					csChange:       1,
					txNBits:        24,
					rxNBits:        24,
					wordDelayUSecs: 0x10,
				},
			},
		},
		{
			name: "TwoTransfers",
			transfers: []Transfer{
				{
					Tx: []uint8{1, 2, 3},
					Rx: []uint8{0, 0, 0},
				},
				{
					Tx: []uint8{4, 5, 6, 7},
				},
			},
			wantTransfers: []iocTransfer{
				{
					txBuf:  0xdeadbeef,
					rxBuf:  0xdeadbeef,
					length: 3,
				},
				{
					txBuf:  0xdeadbeef,
					length: 4,
				},
			},
		},
	} {
		t.Run(tt.name, func(t *testing.T) {
			tmpFile, err := os.CreateTemp("", "")
			if err != nil {
				t.Fatalf("Could not create temporary file: %v", err)
			}
			defer os.Remove(tmpFile.Name())

			s, err := Open(tmpFile.Name())
			if err != nil {
				t.Fatalf("Could not open spidev: %v", err)
			}
			defer s.Close()

			m := &mockSpidev{
				forceErrno: tt.forceErrno,
			}
			s.syscall = m.syscall

			gotErr := s.Transfer(tt.transfers)
			if !errors.Is(gotErr, tt.wantErr) {
				t.Errorf("Got Transfer err %q; want %q", gotErr, tt.wantErr)
			}
			if !reflect.DeepEqual(m.transfers, tt.wantTransfers) {
				t.Errorf("Got Transfers %#v; want %#v", m.transfers, tt.wantTransfers)
			}
		})
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 Florian Pigorsch. All rights reserved.
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package findfont

func getFontDirectories() (paths []string) {
	return []string{expandUser("~/Library/Fonts/"), "/Library/Fonts/"}
}
<commit_msg>Fix default font directory list on MacOS Catalina<commit_after>// Copyright 2016 Florian Pigorsch. All rights reserved.
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package findfont

func getFontDirectories() (paths []string) {
	return []string{
		expandUser("~/Library/Fonts/"),
		"/Library/Fonts/",
		"/System/Library/Fonts/",
	}
}
<|endoftext|>


<commit_before>package webhook

import (
	"bytes"
	"fmt"
	"github.com/buger/jsonparser"
	"github.com/kataras/iris"
	"github.com/mailru/easyjson/jwriter"
	"strconv"
	"strings"
)

// easyjson:json
type Notification struct {
	service    string
	recipients []string
	message    string
}

type WebHook struct {
	queue *MessagingQueue
}

func NewWebHook(queue MessagingQueue) WebHook {
	return WebHook{queue: &queue}
}

func (w *WebHook) Process(ctx *iris.Context) {

	input := ctx.Request.Body()
	fmt.Println("\n\n" + string(input) + "\n\n") // TODO: just for debugging, remove later.

	// parse input

	environment, _, _, _ := jsonparser.Get(input, "error", "environment")
	timesOccurred, _ := jsonparser.GetInt(input, "error", "times_occurred")
	errorId, _ := jsonparser.GetInt(input, "error", "id")
	errorUrl, _, _, _ := jsonparser.Get(input, "airbrake_error_url")
	errorMessage, _, _, _ := jsonparser.Get(input, "error", "error_message")

	// create output

	service := "mattermost"
	recipients := []string{"opslog"}
	message := strings.Join(
		[]string{
			"Environment: " + string(environment),
			"Occurrences: " + strconv.FormatInt(timesOccurred, 10),
			"Error ID: " + strconv.FormatInt(errorId, 10),
			"Error URL: " + strings.Replace(string(errorUrl), "\\", "", -1),
			"Error Message: " + strings.Replace(string(errorMessage), "\\", "", -1),
		},
		", ")

	notification := Notification{service, recipients, message}
	writer := jwriter.Writer{}
	notification.MarshalEasyJSON(&writer)

	if writer.Error == nil {
		buf := new(bytes.Buffer)
		writer.DumpTo(buf)
		w.queue.SendMessage(buf.Bytes())
	}

}
<commit_msg>Fix bug, id is being sent as a string, not as an int<commit_after>package webhook

import (
	"bytes"
	"github.com/buger/jsonparser"
	"github.com/kataras/iris"
	"github.com/mailru/easyjson/jwriter"
	"strconv"
	"strings"
)

// easyjson:json
type Notification struct {
	service    string
	recipients []string
	message    string
}

type WebHook struct {
	queue *MessagingQueue
}

func NewWebHook(queue MessagingQueue) WebHook {
	return WebHook{queue: &queue}
}

func (w *WebHook) Process(ctx *iris.Context) {

	input := ctx.Request.Body()

	// parse input

	environment, _, _, _ := jsonparser.Get(input, "error", "environment")
	timesOccurred, _ := jsonparser.GetInt(input, "error", "times_occurred")
	errorId, _, _, _ := jsonparser.Get(input, "error", "id")
	errorUrl, _, _, _ := jsonparser.Get(input, "airbrake_error_url")
	errorMessage, _, _, _ := jsonparser.Get(input, "error", "error_message")

	// create output

	service := "mattermost"
	recipients := []string{"opslog"}
	message := strings.Join(
		[]string{
			"Environment: " + string(environment),
			"Occurrences: " + strconv.FormatInt(timesOccurred, 10),
			"Error ID: " + string(errorId),
			"Error URL: " + strings.Replace(string(errorUrl), "\\", "", -1),
			"Error Message: " + strings.Replace(string(errorMessage), "\\", "", -1),
		},
		", ")

	notification := Notification{service, recipients, message}
	writer := jwriter.Writer{}
	notification.MarshalEasyJSON(&writer)

	if writer.Error == nil {
		buf := new(bytes.Buffer)
		writer.DumpTo(buf)
		w.queue.SendMessage(buf.Bytes())
	}

}
<|endoftext|>


<commit_before>// Copyright the Service Broker Project 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 models

import (
	"encoding/json"
	"errors"
)

type ServiceBrokerHelper interface {
	Provision(instanceId string, details ProvisionDetails, plan PlanDetails) (ServiceInstanceDetails, error)
	Bind(instanceID, bindingID string, details BindDetails) (ServiceBindingCredentials, error)
	BuildInstanceCredentials(bindRecord ServiceBindingCredentials, instanceRecord ServiceInstanceDetails) (map[string]string, error)
	Unbind(details ServiceBindingCredentials) error
	Deprovision(instanceID string, details DeprovisionDetails) error
	PollInstance(instanceID string) (bool, error)
	LastOperationWasDelete(instanceID string) (bool, error)
	ProvisionsAsync() bool
	DeprovisionsAsync() bool
}

type ServiceBroker interface {
	Services() []Service

	Provision(instanceID string, details ProvisionDetails, asyncAllowed bool) (ProvisionedServiceSpec, error)
	Deprovision(instanceID string, details DeprovisionDetails, asyncAllowed bool) (IsAsync, error)

	Bind(instanceID, bindingID string, details BindDetails) (Binding, error)
	Unbind(instanceID, bindingID string, details UnbindDetails) error

	Update(instanceID string, details UpdateDetails, asyncAllowed bool) (IsAsync, error)

	LastOperation(instanceID string) (LastOperation, error)
}

type AccountManager interface {
	CreateAccountInGoogle(instanceID string, bindingID string, details BindDetails, instance ServiceInstanceDetails) (ServiceBindingCredentials, error)
	DeleteAccountFromGoogle(creds ServiceBindingCredentials) error
	BuildInstanceCredentials(bindRecord ServiceBindingCredentials, instanceRecord ServiceInstanceDetails) (map[string]string, error)
}

type GCPCredentials struct {
	Type                string `json:"type"`
	ProjectId           string `json:"project_id"`
	PrivateKeyId        string `json:"private_key_id"`
	PrivateKey          string `json:"private_key"`
	ClientEmail         string `json:"client_email"`
	ClientId            string `json:"client_id"`
	AuthUri             string `json:"auth_uri"`
	TokenUri            string `json:"token_uri"`
	AuthProviderCertUrl string `json:"auth_provider_x509_cert_url"`
	ClientCertUrl       string `json:"client_x509_cert_url"`
}

type IsAsync bool

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

type ProvisionedServiceSpec struct {
	IsAsync      bool
	DashboardURL string
}

type BindDetails struct {
	AppGUID      string                 `json:"app_guid"`
	PlanID       string                 `json:"plan_id"`
	ServiceID    string                 `json:"service_id"`
	BindResource *BindResource          `json:"bind_resource,omitempty"`
	Parameters   map[string]interface{} `json:"parameters,omitempty"`
}

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

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

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

type UpdateDetails struct {
	ServiceID      string                 `json:"service_id"`
	PlanID         string                 `json:"plan_id"`
	Parameters     map[string]interface{} `json:"parameters"`
	PreviousValues PreviousValues         `json:"previous_values"`
}

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

type LastOperation struct {
	State       LastOperationState
	Description string
}

type LastOperationState string

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

type Binding struct {
	Credentials     interface{} `json:"credentials"`
	SyslogDrainURL  string      `json:"syslog_drain_url,omitempty"`
	RouteServiceURL string      `json:"route_service_url,omitempty"`
}

var (
	ErrInstanceAlreadyExists  = errors.New("instance already exists")
	ErrInstanceDoesNotExist   = errors.New("instance does not exist")
	ErrInstanceLimitMet       = errors.New("instance limit for this service has been reached")
	ErrPlanQuotaExceeded      = errors.New("The quota for this service plan has been exceeded. Please contact your Operator for help.")
	ErrBindingAlreadyExists   = errors.New("binding already exists")
	ErrBindingDoesNotExist    = errors.New("binding does not exist")
	ErrAsyncRequired          = errors.New("This service plan requires client support for asynchronous service operations.")
	ErrServiceIsNotAsync      = errors.New("This service is not provisioned asynchronously; this operation does not apply.")
	ErrPlanChangeNotSupported = errors.New("The requested plan migration cannot be performed")
	ErrRawParamsInvalid       = errors.New("The format of the parameters is not valid JSON")
	ErrAppGuidNotProvided     = errors.New("app_guid is a required field but was not provided")
)

// This custom user agent string is added to provision calls so that Google can track the aggregated use of this tool
// We can better advocate for devoting resources to supporting cloud foundry and this service broker if we can show
// good usage statistics for it, so if you feel the need to fork this repo, please leave this string in place!
var CustomUserAgent = "cf-gcp-service-broker-test 3.5.2"

func ProductionizeUserAgent() {
	CustomUserAgent = "cf-gcp-service-broker 3.5.2"
}

const CloudPlatformScope = "https://www.googleapis.com/auth/cloud-platform"
const StorageName = "google-storage"
const BigqueryName = "google-bigquery"
const BigtableName = "google-bigtable"
const CloudsqlMySQLName = "google-cloudsql-mysql"
const CloudsqlPostgresName = "google-cloudsql-postgres"
const PubsubName = "google-pubsub"
const MlName = "google-ml-apis"
const SpannerName = "google-spanner"
const StackdriverTraceName = "google-stackdriver-trace"
const StackdriverDebuggerName = "google-stackdriver-debugger"
const DatastoreName = "google-datastore"
const AppCredsEnvVar = "GOOGLE_APPLICATION_CREDENTIALS"
const AppCredsFileName = "application-default-credentials.json"
const RootSaEnvVar = "ROOT_SERVICE_ACCOUNT_JSON"
<commit_msg>Update user agent string with new version<commit_after>// Copyright the Service Broker Project 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 models

import (
	"encoding/json"
	"errors"
)

type ServiceBrokerHelper interface {
	Provision(instanceId string, details ProvisionDetails, plan PlanDetails) (ServiceInstanceDetails, error)
	Bind(instanceID, bindingID string, details BindDetails) (ServiceBindingCredentials, error)
	BuildInstanceCredentials(bindRecord ServiceBindingCredentials, instanceRecord ServiceInstanceDetails) (map[string]string, error)
	Unbind(details ServiceBindingCredentials) error
	Deprovision(instanceID string, details DeprovisionDetails) error
	PollInstance(instanceID string) (bool, error)
	LastOperationWasDelete(instanceID string) (bool, error)
	ProvisionsAsync() bool
	DeprovisionsAsync() bool
}

type ServiceBroker interface {
	Services() []Service

	Provision(instanceID string, details ProvisionDetails, asyncAllowed bool) (ProvisionedServiceSpec, error)
	Deprovision(instanceID string, details DeprovisionDetails, asyncAllowed bool) (IsAsync, error)

	Bind(instanceID, bindingID string, details BindDetails) (Binding, error)
	Unbind(instanceID, bindingID string, details UnbindDetails) error

	Update(instanceID string, details UpdateDetails, asyncAllowed bool) (IsAsync, error)

	LastOperation(instanceID string) (LastOperation, error)
}

type AccountManager interface {
	CreateAccountInGoogle(instanceID string, bindingID string, details BindDetails, instance ServiceInstanceDetails) (ServiceBindingCredentials, error)
	DeleteAccountFromGoogle(creds ServiceBindingCredentials) error
	BuildInstanceCredentials(bindRecord ServiceBindingCredentials, instanceRecord ServiceInstanceDetails) (map[string]string, error)
}

type GCPCredentials struct {
	Type                string `json:"type"`
	ProjectId           string `json:"project_id"`
	PrivateKeyId        string `json:"private_key_id"`
	PrivateKey          string `json:"private_key"`
	ClientEmail         string `json:"client_email"`
	ClientId            string `json:"client_id"`
	AuthUri             string `json:"auth_uri"`
	TokenUri            string `json:"token_uri"`
	AuthProviderCertUrl string `json:"auth_provider_x509_cert_url"`
	ClientCertUrl       string `json:"client_x509_cert_url"`
}

type IsAsync bool

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

type ProvisionedServiceSpec struct {
	IsAsync      bool
	DashboardURL string
}

type BindDetails struct {
	AppGUID      string                 `json:"app_guid"`
	PlanID       string                 `json:"plan_id"`
	ServiceID    string                 `json:"service_id"`
	BindResource *BindResource          `json:"bind_resource,omitempty"`
	Parameters   map[string]interface{} `json:"parameters,omitempty"`
}

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

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

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

type UpdateDetails struct {
	ServiceID      string                 `json:"service_id"`
	PlanID         string                 `json:"plan_id"`
	Parameters     map[string]interface{} `json:"parameters"`
	PreviousValues PreviousValues         `json:"previous_values"`
}

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

type LastOperation struct {
	State       LastOperationState
	Description string
}

type LastOperationState string

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

type Binding struct {
	Credentials     interface{} `json:"credentials"`
	SyslogDrainURL  string      `json:"syslog_drain_url,omitempty"`
	RouteServiceURL string      `json:"route_service_url,omitempty"`
}

var (
	ErrInstanceAlreadyExists  = errors.New("instance already exists")
	ErrInstanceDoesNotExist   = errors.New("instance does not exist")
	ErrInstanceLimitMet       = errors.New("instance limit for this service has been reached")
	ErrPlanQuotaExceeded      = errors.New("The quota for this service plan has been exceeded. Please contact your Operator for help.")
	ErrBindingAlreadyExists   = errors.New("binding already exists")
	ErrBindingDoesNotExist    = errors.New("binding does not exist")
	ErrAsyncRequired          = errors.New("This service plan requires client support for asynchronous service operations.")
	ErrServiceIsNotAsync      = errors.New("This service is not provisioned asynchronously; this operation does not apply.")
	ErrPlanChangeNotSupported = errors.New("The requested plan migration cannot be performed")
	ErrRawParamsInvalid       = errors.New("The format of the parameters is not valid JSON")
	ErrAppGuidNotProvided     = errors.New("app_guid is a required field but was not provided")
)

// This custom user agent string is added to provision calls so that Google can track the aggregated use of this tool
// We can better advocate for devoting resources to supporting cloud foundry and this service broker if we can show
// good usage statistics for it, so if you feel the need to fork this repo, please leave this string in place!
var CustomUserAgent = "cf-gcp-service-broker-test 3.6.0"

func ProductionizeUserAgent() {
	CustomUserAgent = "cf-gcp-service-broker 3.6.0"
}

const CloudPlatformScope = "https://www.googleapis.com/auth/cloud-platform"
const StorageName = "google-storage"
const BigqueryName = "google-bigquery"
const BigtableName = "google-bigtable"
const CloudsqlMySQLName = "google-cloudsql-mysql"
const CloudsqlPostgresName = "google-cloudsql-postgres"
const PubsubName = "google-pubsub"
const MlName = "google-ml-apis"
const SpannerName = "google-spanner"
const StackdriverTraceName = "google-stackdriver-trace"
const StackdriverDebuggerName = "google-stackdriver-debugger"
const DatastoreName = "google-datastore"
const AppCredsEnvVar = "GOOGLE_APPLICATION_CREDENTIALS"
const AppCredsFileName = "application-default-credentials.json"
const RootSaEnvVar = "ROOT_SERVICE_ACCOUNT_JSON"
<|endoftext|>