<commit_before>package elasticsearch

import (
	"encoding/json"
	"fmt"

	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/intstr"
	apiv1 "k8s.io/client-go/pkg/api/v1"
	apps "k8s.io/client-go/pkg/apis/apps/v1beta1"
	extensions "k8s.io/client-go/pkg/apis/extensions/v1beta1"

	"gitlab.jetstack.net/marshal/colonel/pkg/api/v1"
)

const (
	typeName = "es"
	kindName = "ElasticsearchCluster"

	nodePoolVersionAnnotationKey = "elasticsearch.marshal.io/deployed-version"
)

var (
	trueVar  = true
	falseVar = false
)

func int32Ptr(i int32) *int32 {
	return &i
}

func int64Ptr(i int64) *int64 {
	return &i
}

func elasticsearchPodTemplateSpec(c *v1.ElasticsearchCluster, np *v1.ElasticsearchClusterNodePool) (*apiv1.PodTemplateSpec, error) {
	initContainers := buildInitContainers(c, np)

	initContainersJSON, err := json.Marshal(initContainers)

	if err != nil {
		return nil, fmt.Errorf("error marshaling init containers: %s", err.Error())
	}

	elasticsearchContainerRequests, elasticsearchContainerLimits :=
		apiv1.ResourceList{},
		apiv1.ResourceList{}

	if np.Resources != nil {
		if req := np.Resources.Requests; req != nil {
			elasticsearchContainerRequests, err = parseResources(req)

			if err != nil {
				return nil, fmt.Errorf("error parsing container resource requests: %s", err.Error())
			}
		}
		if req := np.Resources.Limits; req != nil {
			elasticsearchContainerLimits, err = parseResources(req)

			if err != nil {
				return nil, fmt.Errorf("error parsing container resource limits: %s", err.Error())
			}
		}
	}

	volumes := []apiv1.Volume{
	// {
	// 	Name: "sidecar-config",
	// 	VolumeSource: apiv1.VolumeSource{
	// 		ConfigMap: &apiv1.ConfigMapVolumeSource{
	// 			LocalObjectReference: apiv1.LocalObjectReference{
	// 				Name: nodePoolConfigMapName(c, np),
	// 			},
	// 		},
	// 	},
	// },
	}

	if np.State == nil ||
		np.State.Persistence == nil ||
		!np.State.Persistence.Enabled {
		volumes = append(volumes, apiv1.Volume{
			Name: "elasticsearch-data",
			VolumeSource: apiv1.VolumeSource{
				EmptyDir: &apiv1.EmptyDirVolumeSource{},
			},
		})
	}

	return &apiv1.PodTemplateSpec{
		ObjectMeta: metav1.ObjectMeta{
			Labels: buildNodePoolLabels(c, np.Name, np.Roles...),
			Annotations: map[string]string{
				"pod.beta.kubernetes.io/init-containers": string(initContainersJSON),
			},
		},
		Spec: apiv1.PodSpec{
			TerminationGracePeriodSeconds: int64Ptr(1800),
			// TODO
			ServiceAccountName: "",
			SecurityContext: &apiv1.PodSecurityContext{
				FSGroup: int64Ptr(c.Spec.Image.FsGroup),
			},
			Volumes: volumes,
			Containers: []apiv1.Container{
				{
					Name:            "elasticsearch",
					Image:           c.Spec.Image.Repository + ":" + c.Spec.Image.Tag,
					ImagePullPolicy: apiv1.PullPolicy(c.Spec.Image.PullPolicy),
					Args:            []string{"start"},
					Env: []apiv1.EnvVar{
						// TODO: Tidy up generation of discovery & client URLs
						{
							Name:  "DISCOVERY_HOST",
							Value: clusterService(c, "discovery", false, nil, "master").Name,
						},
						{
							Name:  "CLUSTER_URL",
							Value: "http://" + clusterService(c, "clients", true, nil, "client").Name + ":9200",
						},
						apiv1.EnvVar{
							Name: "POD_NAME",
							ValueFrom: &apiv1.EnvVarSource{
								FieldRef: &apiv1.ObjectFieldSelector{
									FieldPath: "metadata.name",
								},
							},
						},
						apiv1.EnvVar{
							Name: "NAMESPACE",
							ValueFrom: &apiv1.EnvVarSource{
								FieldRef: &apiv1.ObjectFieldSelector{
									FieldPath: "metadata.namespace",
								},
							},
						},
					},
					SecurityContext: &apiv1.SecurityContext{
						Capabilities: &apiv1.Capabilities{
							Add: []apiv1.Capability{
								apiv1.Capability("IPC_LOCK"),
							},
						},
					},
					ReadinessProbe: &apiv1.Probe{
						Handler: apiv1.Handler{
							HTTPGet: &apiv1.HTTPGetAction{
								Port: intstr.FromInt(12001),
								Path: "/",
							},
						},
						InitialDelaySeconds: int32(60),
						PeriodSeconds:       int32(10),
						TimeoutSeconds:      int32(5),
					},
					LivenessProbe: &apiv1.Probe{
						Handler: apiv1.Handler{
							HTTPGet: &apiv1.HTTPGetAction{
								Port: intstr.FromInt(12000),
								Path: "/",
							},
						},
						InitialDelaySeconds: int32(60),
						PeriodSeconds:       int32(10),
						TimeoutSeconds:      int32(5),
					},
					Resources: apiv1.ResourceRequirements{
						Requests: elasticsearchContainerRequests,
						Limits:   elasticsearchContainerLimits,
					},
					Ports: []apiv1.ContainerPort{
						{
							Name:          "transport",
							ContainerPort: int32(9300),
						},
						{
							Name:          "http",
							ContainerPort: int32(9200),
						},
					},
					VolumeMounts: []apiv1.VolumeMount{
						{
							Name:      "elasticsearch-data",
							MountPath: "/usr/share/elasticsearch/data",
							ReadOnly:  false,
						},
					},
				},
			},
		},
	}, nil
}

func buildInitContainers(c *v1.ElasticsearchCluster, np *v1.ElasticsearchClusterNodePool) []apiv1.Container {
	containers := make([]apiv1.Container, len(c.Spec.Sysctl))
	for i, sysctl := range c.Spec.Sysctl {
		containers[i] = apiv1.Container{
			Name:            fmt.Sprintf("tune-sysctl-%d", i),
			Image:           "busybox:latest",
			ImagePullPolicy: apiv1.PullIfNotPresent,
			SecurityContext: &apiv1.SecurityContext{
				Privileged: &trueVar,
			},
			Command: []string{
				"sysctl", "-w", sysctl,
			},
		}
	}
	return containers
}

func buildNodePoolLabels(c *v1.ElasticsearchCluster, poolName string, roles ...string) map[string]string {
	labels := map[string]string{
		"app": "elasticsearch",
	}
	if poolName != "" {
		labels["pool"] = poolName
	}
	for _, role := range roles {
		labels[role] = "true"
	}
	return labels
}

func parseResources(rs *v1.ElasticsearchClusterResources_ResourceSet) (apiv1.ResourceList, error) {
	list := apiv1.ResourceList{}
	var err error
	var cpu, mem resource.Quantity

	if cpu, err = resource.ParseQuantity(rs.Cpu); err != nil {
		return list, fmt.Errorf("error parsing cpu specification '%s': %s", rs.Cpu, err.Error())
	}

	list[apiv1.ResourceCPU] = cpu

	if mem, err = resource.ParseQuantity(rs.Memory); err != nil {
		return list, fmt.Errorf("error parsing memory specification '%s': %s", rs.Memory, err.Error())
	}

	list[apiv1.ResourceMemory] = mem

	return list, nil
}

func clusterService(c *v1.ElasticsearchCluster, name string, http bool, annotations map[string]string, roles ...string) *apiv1.Service {
	svc := apiv1.Service{
		ObjectMeta: metav1.ObjectMeta{
			Name:            c.Name + "-" + name,
			Namespace:       c.Namespace,
			OwnerReferences: []metav1.OwnerReference{ownerReference(c)},
			Labels:          buildNodePoolLabels(c, "", roles...),
			Annotations:     annotations,
		},
		Spec: apiv1.ServiceSpec{
			Type: apiv1.ServiceTypeClusterIP,
			Ports: []apiv1.ServicePort{
				{
					Name:       "transport",
					Port:       int32(9300),
					TargetPort: intstr.FromInt(9300),
				},
			},
			Selector: buildNodePoolLabels(c, "", roles...),
		},
	}

	if http {
		svc.Spec.Ports = append(svc.Spec.Ports, apiv1.ServicePort{
			Name:       "http",
			Port:       int32(9200),
			TargetPort: intstr.FromInt(9200),
		})
	}

	return &svc
}

func nodePoolDeployment(c *v1.ElasticsearchCluster, np *v1.ElasticsearchClusterNodePool) (*extensions.Deployment, error) {
	elasticsearchPodTemplate, err := elasticsearchPodTemplateSpec(c, np)

	if err != nil {
		return nil, fmt.Errorf("error building elasticsearch container: %s", err.Error())
	}

	deploymentName := nodePoolResourceName(c, np)
	depl := &extensions.Deployment{
		ObjectMeta: metav1.ObjectMeta{
			Name:            deploymentName,
			Namespace:       c.Namespace,
			OwnerReferences: []metav1.OwnerReference{ownerReference(c)},
			Annotations: map[string]string{
				nodePoolVersionAnnotationKey: c.Spec.Version,
			},
			Labels: buildNodePoolLabels(c, np.Name, np.Roles...),
		},
		Spec: extensions.DeploymentSpec{
			Replicas: int32Ptr(int32(np.Replicas)),
			Selector: &metav1.LabelSelector{
				MatchLabels: buildNodePoolLabels(c, np.Name, np.Roles...),
			},
			Template: *elasticsearchPodTemplate,
		},
	}

	// TODO: make this safer?
	depl.Spec.Template.Spec.Containers[0].Args = append(
		depl.Spec.Template.Spec.Containers[0].Args,
		"--controllerKind=Deployment",
		"--controllerName="+deploymentName,
	)
	return depl, nil
}

func nodePoolStatefulSet(c *v1.ElasticsearchCluster, np *v1.ElasticsearchClusterNodePool) (*apps.StatefulSet, error) {
	volumeClaimTemplateAnnotations, volumeResourceRequests := map[string]string{}, apiv1.ResourceList{}

	if np.State.Persistence != nil {
		if np.State.Persistence.StorageClass != "" {
			volumeClaimTemplateAnnotations["volume.beta.kubernetes.io/storage-class"] = np.State.Persistence.StorageClass
		}

		if size := np.State.Persistence.Size; size != "" {
			storageRequests, err := resource.ParseQuantity(size)

			if err != nil {
				return nil, fmt.Errorf("error parsing storage size quantity '%s': %s", size, err.Error())
			}

			volumeResourceRequests[apiv1.ResourceStorage] = storageRequests
		}
	}

	elasticsearchPodTemplate, err := elasticsearchPodTemplateSpec(c, np)

	if err != nil {
		return nil, fmt.Errorf("error building elasticsearch container: %s", err.Error())
	}

	statefulSetName := nodePoolResourceName(c, np)

	ss := &apps.StatefulSet{
		ObjectMeta: metav1.ObjectMeta{
			Name:            statefulSetName,
			Namespace:       c.Namespace,
			OwnerReferences: []metav1.OwnerReference{ownerReference(c)},
			Annotations: map[string]string{
				nodePoolVersionAnnotationKey: c.Spec.Version,
			},
			Labels: buildNodePoolLabels(c, np.Name, np.Roles...),
		},
		Spec: apps.StatefulSetSpec{
			Replicas:    int32Ptr(int32(np.Replicas)),
			ServiceName: statefulSetName,
			Selector: &metav1.LabelSelector{
				MatchLabels: buildNodePoolLabels(c, np.Name, np.Roles...),
			},
			Template: *elasticsearchPodTemplate,
			VolumeClaimTemplates: []apiv1.PersistentVolumeClaim{
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:        "elasticsearch-data",
						Annotations: volumeClaimTemplateAnnotations,
					},
					Spec: apiv1.PersistentVolumeClaimSpec{
						AccessModes: []apiv1.PersistentVolumeAccessMode{
							apiv1.ReadWriteOnce,
						},
						Resources: apiv1.ResourceRequirements{
							Requests: volumeResourceRequests,
						},
					},
				},
			},
		},
	}

	// TODO: make this safer?
	ss.Spec.Template.Spec.Containers[0].Args = append(
		ss.Spec.Template.Spec.Containers[0].Args,
		"--controllerKind=StatefulSet",
		"--controllerName="+statefulSetName,
	)

	return ss, nil
}

func clusterServiceAccount(c *v1.ElasticsearchCluster) *apiv1.ServiceAccount {
	return &apiv1.ServiceAccount{
		ObjectMeta: metav1.ObjectMeta{
			Name:            resourceBaseName(c),
			Namespace:       c.Namespace,
			OwnerReferences: []metav1.OwnerReference{ownerReference(c)},
		},
	}
}

func isManagedByCluster(c *v1.ElasticsearchCluster, meta metav1.ObjectMeta) bool {
	clusterOwnerRef := ownerReference(c)
	for _, o := range meta.OwnerReferences {
		if clusterOwnerRef.APIVersion == o.APIVersion &&
			clusterOwnerRef.Kind == o.Kind &&
			clusterOwnerRef.Name == o.Name &&
			clusterOwnerRef.UID == o.UID {
			return true
		}
	}
	return false
}

func managedOwnerRef(meta metav1.ObjectMeta) *metav1.OwnerReference {
	for _, ref := range meta.OwnerReferences {
		if ref.APIVersion == v1.GroupName+"/"+v1.Version && ref.Kind == kindName {
			return &ref
		}
	}
	return nil
}

func ownerReference(c *v1.ElasticsearchCluster) metav1.OwnerReference {
	// Really, this should be able to use the TypeMeta of the ElasticsearchCluster.
	// There is an issue open on client-go about this here: https://github.com/kubernetes/client-go/issues/60
	return metav1.OwnerReference{
		APIVersion: v1.GroupName + "/" + v1.Version,
		Kind:       kindName,
		Name:       c.Name,
		UID:        c.UID,
	}
}

func resourceBaseName(c *v1.ElasticsearchCluster) string {
	return typeName + "-" + c.Name
}

func nodePoolResourceName(c *v1.ElasticsearchCluster, np *v1.ElasticsearchClusterNodePool) string {
	return fmt.Sprintf("%s-%s", resourceBaseName(c), np.Name)
}

func nodePoolVersionAnnotation(m map[string]string) string {
	return m[nodePoolVersionAnnotationKey]
}

func nodePoolIsStateful(np *v1.ElasticsearchClusterNodePool) bool {
	if np.State != nil && np.State.Stateful {
		return true
	}
	return false
}
<commit_msg>Set elasticsearch args<commit_after>package elasticsearch

import (
	"encoding/json"
	"fmt"

	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/intstr"
	apiv1 "k8s.io/client-go/pkg/api/v1"
	apps "k8s.io/client-go/pkg/apis/apps/v1beta1"
	extensions "k8s.io/client-go/pkg/apis/extensions/v1beta1"

	"gitlab.jetstack.net/marshal/colonel/pkg/api/v1"
)

const (
	typeName = "es"
	kindName = "ElasticsearchCluster"

	nodePoolVersionAnnotationKey = "elasticsearch.marshal.io/deployed-version"
)

var (
	trueVar  = true
	falseVar = false
)

func int32Ptr(i int32) *int32 {
	return &i
}

func int64Ptr(i int64) *int64 {
	return &i
}

func elasticsearchPodTemplateSpec(c *v1.ElasticsearchCluster, np *v1.ElasticsearchClusterNodePool) (*apiv1.PodTemplateSpec, error) {
	initContainers := buildInitContainers(c, np)

	initContainersJSON, err := json.Marshal(initContainers)

	if err != nil {
		return nil, fmt.Errorf("error marshaling init containers: %s", err.Error())
	}

	elasticsearchContainerRequests, elasticsearchContainerLimits :=
		apiv1.ResourceList{},
		apiv1.ResourceList{}

	if np.Resources != nil {
		if req := np.Resources.Requests; req != nil {
			elasticsearchContainerRequests, err = parseResources(req)

			if err != nil {
				return nil, fmt.Errorf("error parsing container resource requests: %s", err.Error())
			}
		}
		if req := np.Resources.Limits; req != nil {
			elasticsearchContainerLimits, err = parseResources(req)

			if err != nil {
				return nil, fmt.Errorf("error parsing container resource limits: %s", err.Error())
			}
		}
	}

	volumes := []apiv1.Volume{}

	if np.State == nil ||
		np.State.Persistence == nil ||
		!np.State.Persistence.Enabled {
		volumes = append(volumes, apiv1.Volume{
			Name: "elasticsearch-data",
			VolumeSource: apiv1.VolumeSource{
				EmptyDir: &apiv1.EmptyDirVolumeSource{},
			},
		})
	}

	rolesBytes, err := json.Marshal(np.Roles)

	if err != nil {
		return nil, fmt.Errorf("error marshaling roles: %s", err.Error())
	}

	pluginsBytes, err := json.Marshal(c.Spec.Plugins)

	if err != nil {
		return nil, fmt.Errorf("error marshaling plugins: %s", err.Error())
	}

	return &apiv1.PodTemplateSpec{
		ObjectMeta: metav1.ObjectMeta{
			Labels: buildNodePoolLabels(c, np.Name, np.Roles...),
			Annotations: map[string]string{
				"pod.beta.kubernetes.io/init-containers": string(initContainersJSON),
			},
		},
		Spec: apiv1.PodSpec{
			TerminationGracePeriodSeconds: int64Ptr(1800),
			// TODO
			ServiceAccountName: "",
			SecurityContext: &apiv1.PodSecurityContext{
				FSGroup: int64Ptr(c.Spec.Image.FsGroup),
			},
			Volumes: volumes,
			Containers: []apiv1.Container{
				{
					Name:            "elasticsearch",
					Image:           c.Spec.Image.Repository + ":" + c.Spec.Image.Tag,
					ImagePullPolicy: apiv1.PullPolicy(c.Spec.Image.PullPolicy),
					Args: []string{
						"start",
						"--podName=$(POD_NAME)",
						"--clusterURL=$(CLUSTER_URL)",
						"--namespace=$(NAMESPACE)",
						"--plugins=" + string(pluginsBytes),
						"--roles=" + string(rolesBytes),
					},
					Env: []apiv1.EnvVar{
						// TODO: Tidy up generation of discovery & client URLs
						{
							Name:  "DISCOVERY_HOST",
							Value: clusterService(c, "discovery", false, nil, "master").Name,
						},
						{
							Name:  "CLUSTER_URL",
							Value: "http://" + clusterService(c, "clients", true, nil, "client").Name + ":9200",
						},
						apiv1.EnvVar{
							Name: "POD_NAME",
							ValueFrom: &apiv1.EnvVarSource{
								FieldRef: &apiv1.ObjectFieldSelector{
									FieldPath: "metadata.name",
								},
							},
						},
						apiv1.EnvVar{
							Name: "NAMESPACE",
							ValueFrom: &apiv1.EnvVarSource{
								FieldRef: &apiv1.ObjectFieldSelector{
									FieldPath: "metadata.namespace",
								},
							},
						},
					},
					SecurityContext: &apiv1.SecurityContext{
						Capabilities: &apiv1.Capabilities{
							Add: []apiv1.Capability{
								apiv1.Capability("IPC_LOCK"),
							},
						},
					},
					ReadinessProbe: &apiv1.Probe{
						Handler: apiv1.Handler{
							HTTPGet: &apiv1.HTTPGetAction{
								Port: intstr.FromInt(12001),
								Path: "/",
							},
						},
						InitialDelaySeconds: int32(60),
						PeriodSeconds:       int32(10),
						TimeoutSeconds:      int32(5),
					},
					LivenessProbe: &apiv1.Probe{
						Handler: apiv1.Handler{
							HTTPGet: &apiv1.HTTPGetAction{
								Port: intstr.FromInt(12000),
								Path: "/",
							},
						},
						InitialDelaySeconds: int32(60),
						PeriodSeconds:       int32(10),
						TimeoutSeconds:      int32(5),
					},
					Resources: apiv1.ResourceRequirements{
						Requests: elasticsearchContainerRequests,
						Limits:   elasticsearchContainerLimits,
					},
					Ports: []apiv1.ContainerPort{
						{
							Name:          "transport",
							ContainerPort: int32(9300),
						},
						{
							Name:          "http",
							ContainerPort: int32(9200),
						},
					},
					VolumeMounts: []apiv1.VolumeMount{
						{
							Name:      "elasticsearch-data",
							MountPath: "/usr/share/elasticsearch/data",
							ReadOnly:  false,
						},
					},
				},
			},
		},
	}, nil
}

func buildInitContainers(c *v1.ElasticsearchCluster, np *v1.ElasticsearchClusterNodePool) []apiv1.Container {
	containers := make([]apiv1.Container, len(c.Spec.Sysctl))
	for i, sysctl := range c.Spec.Sysctl {
		containers[i] = apiv1.Container{
			Name:            fmt.Sprintf("tune-sysctl-%d", i),
			Image:           "busybox:latest",
			ImagePullPolicy: apiv1.PullIfNotPresent,
			SecurityContext: &apiv1.SecurityContext{
				Privileged: &trueVar,
			},
			Command: []string{
				"sysctl", "-w", sysctl,
			},
		}
	}
	return containers
}

func buildNodePoolLabels(c *v1.ElasticsearchCluster, poolName string, roles ...string) map[string]string {
	labels := map[string]string{
		"app": "elasticsearch",
	}
	if poolName != "" {
		labels["pool"] = poolName
	}
	for _, role := range roles {
		labels[role] = "true"
	}
	return labels
}

func parseResources(rs *v1.ElasticsearchClusterResources_ResourceSet) (apiv1.ResourceList, error) {
	list := apiv1.ResourceList{}
	var err error
	var cpu, mem resource.Quantity

	if cpu, err = resource.ParseQuantity(rs.Cpu); err != nil {
		return list, fmt.Errorf("error parsing cpu specification '%s': %s", rs.Cpu, err.Error())
	}

	list[apiv1.ResourceCPU] = cpu

	if mem, err = resource.ParseQuantity(rs.Memory); err != nil {
		return list, fmt.Errorf("error parsing memory specification '%s': %s", rs.Memory, err.Error())
	}

	list[apiv1.ResourceMemory] = mem

	return list, nil
}

func clusterService(c *v1.ElasticsearchCluster, name string, http bool, annotations map[string]string, roles ...string) *apiv1.Service {
	svc := apiv1.Service{
		ObjectMeta: metav1.ObjectMeta{
			Name:            c.Name + "-" + name,
			Namespace:       c.Namespace,
			OwnerReferences: []metav1.OwnerReference{ownerReference(c)},
			Labels:          buildNodePoolLabels(c, "", roles...),
			Annotations:     annotations,
		},
		Spec: apiv1.ServiceSpec{
			Type: apiv1.ServiceTypeClusterIP,
			Ports: []apiv1.ServicePort{
				{
					Name:       "transport",
					Port:       int32(9300),
					TargetPort: intstr.FromInt(9300),
				},
			},
			Selector: buildNodePoolLabels(c, "", roles...),
		},
	}

	if http {
		svc.Spec.Ports = append(svc.Spec.Ports, apiv1.ServicePort{
			Name:       "http",
			Port:       int32(9200),
			TargetPort: intstr.FromInt(9200),
		})
	}

	return &svc
}

func nodePoolDeployment(c *v1.ElasticsearchCluster, np *v1.ElasticsearchClusterNodePool) (*extensions.Deployment, error) {
	elasticsearchPodTemplate, err := elasticsearchPodTemplateSpec(c, np)

	if err != nil {
		return nil, fmt.Errorf("error building elasticsearch container: %s", err.Error())
	}

	deploymentName := nodePoolResourceName(c, np)
	depl := &extensions.Deployment{
		ObjectMeta: metav1.ObjectMeta{
			Name:            deploymentName,
			Namespace:       c.Namespace,
			OwnerReferences: []metav1.OwnerReference{ownerReference(c)},
			Annotations: map[string]string{
				nodePoolVersionAnnotationKey: c.Spec.Version,
			},
			Labels: buildNodePoolLabels(c, np.Name, np.Roles...),
		},
		Spec: extensions.DeploymentSpec{
			Replicas: int32Ptr(int32(np.Replicas)),
			Selector: &metav1.LabelSelector{
				MatchLabels: buildNodePoolLabels(c, np.Name, np.Roles...),
			},
			Template: *elasticsearchPodTemplate,
		},
	}

	// TODO: make this safer?
	depl.Spec.Template.Spec.Containers[0].Args = append(
		depl.Spec.Template.Spec.Containers[0].Args,
		"--controllerKind=Deployment",
		"--controllerName="+deploymentName,
	)
	return depl, nil
}

func nodePoolStatefulSet(c *v1.ElasticsearchCluster, np *v1.ElasticsearchClusterNodePool) (*apps.StatefulSet, error) {
	volumeClaimTemplateAnnotations, volumeResourceRequests := map[string]string{}, apiv1.ResourceList{}

	if np.State.Persistence != nil {
		if np.State.Persistence.StorageClass != "" {
			volumeClaimTemplateAnnotations["volume.beta.kubernetes.io/storage-class"] = np.State.Persistence.StorageClass
		}

		if size := np.State.Persistence.Size; size != "" {
			storageRequests, err := resource.ParseQuantity(size)

			if err != nil {
				return nil, fmt.Errorf("error parsing storage size quantity '%s': %s", size, err.Error())
			}

			volumeResourceRequests[apiv1.ResourceStorage] = storageRequests
		}
	}

	elasticsearchPodTemplate, err := elasticsearchPodTemplateSpec(c, np)

	if err != nil {
		return nil, fmt.Errorf("error building elasticsearch container: %s", err.Error())
	}

	statefulSetName := nodePoolResourceName(c, np)

	ss := &apps.StatefulSet{
		ObjectMeta: metav1.ObjectMeta{
			Name:            statefulSetName,
			Namespace:       c.Namespace,
			OwnerReferences: []metav1.OwnerReference{ownerReference(c)},
			Annotations: map[string]string{
				nodePoolVersionAnnotationKey: c.Spec.Version,
			},
			Labels: buildNodePoolLabels(c, np.Name, np.Roles...),
		},
		Spec: apps.StatefulSetSpec{
			Replicas:    int32Ptr(int32(np.Replicas)),
			ServiceName: statefulSetName,
			Selector: &metav1.LabelSelector{
				MatchLabels: buildNodePoolLabels(c, np.Name, np.Roles...),
			},
			Template: *elasticsearchPodTemplate,
			VolumeClaimTemplates: []apiv1.PersistentVolumeClaim{
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:        "elasticsearch-data",
						Annotations: volumeClaimTemplateAnnotations,
					},
					Spec: apiv1.PersistentVolumeClaimSpec{
						AccessModes: []apiv1.PersistentVolumeAccessMode{
							apiv1.ReadWriteOnce,
						},
						Resources: apiv1.ResourceRequirements{
							Requests: volumeResourceRequests,
						},
					},
				},
			},
		},
	}

	// TODO: make this safer?
	ss.Spec.Template.Spec.Containers[0].Args = append(
		ss.Spec.Template.Spec.Containers[0].Args,
		"--controllerKind=StatefulSet",
		"--controllerName="+statefulSetName,
	)

	return ss, nil
}

func clusterServiceAccount(c *v1.ElasticsearchCluster) *apiv1.ServiceAccount {
	return &apiv1.ServiceAccount{
		ObjectMeta: metav1.ObjectMeta{
			Name:            resourceBaseName(c),
			Namespace:       c.Namespace,
			OwnerReferences: []metav1.OwnerReference{ownerReference(c)},
		},
	}
}

func isManagedByCluster(c *v1.ElasticsearchCluster, meta metav1.ObjectMeta) bool {
	clusterOwnerRef := ownerReference(c)
	for _, o := range meta.OwnerReferences {
		if clusterOwnerRef.APIVersion == o.APIVersion &&
			clusterOwnerRef.Kind == o.Kind &&
			clusterOwnerRef.Name == o.Name &&
			clusterOwnerRef.UID == o.UID {
			return true
		}
	}
	return false
}

func managedOwnerRef(meta metav1.ObjectMeta) *metav1.OwnerReference {
	for _, ref := range meta.OwnerReferences {
		if ref.APIVersion == v1.GroupName+"/"+v1.Version && ref.Kind == kindName {
			return &ref
		}
	}
	return nil
}

func ownerReference(c *v1.ElasticsearchCluster) metav1.OwnerReference {
	// Really, this should be able to use the TypeMeta of the ElasticsearchCluster.
	// There is an issue open on client-go about this here: https://github.com/kubernetes/client-go/issues/60
	return metav1.OwnerReference{
		APIVersion: v1.GroupName + "/" + v1.Version,
		Kind:       kindName,
		Name:       c.Name,
		UID:        c.UID,
	}
}

func resourceBaseName(c *v1.ElasticsearchCluster) string {
	return typeName + "-" + c.Name
}

func nodePoolResourceName(c *v1.ElasticsearchCluster, np *v1.ElasticsearchClusterNodePool) string {
	return fmt.Sprintf("%s-%s", resourceBaseName(c), np.Name)
}

func nodePoolVersionAnnotation(m map[string]string) string {
	return m[nodePoolVersionAnnotationKey]
}

func nodePoolIsStateful(np *v1.ElasticsearchClusterNodePool) bool {
	if np.State != nil && np.State.Stateful {
		return true
	}
	return false
}
<|endoftext|>


<commit_before>// Package exp11 displays Go package source code with dot imports inlined.
package exp11

import (
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"io"
	"os"
	"strings"

	"golang.org/x/tools/go/loader"
	"golang.org/x/tools/imports"

	//"golang.org/x/tools/go/types"
	//"honnef.co/go/importer"

	. "github.com/shurcooL/go/gists/gist5504644"
	. "github.com/shurcooL/go/gists/gist5639599"

	"github.com/shurcooL/go/exp/15"
)

var _ = AstPackageFromBuildPackage
var _ = PrintlnAst
var _ = exp15.SortImports

const parserMode = parser.ParseComments
const astMergeMode = 0*ast.FilterFuncDuplicates | ast.FilterUnassociatedComments | ast.FilterImportDuplicates

var dotImports []*loader.PackageInfo

func findDotImports(prog *loader.Program, pi *loader.PackageInfo) {
	for _, file := range pi.Files {
		for _, importSpec := range file.Imports {
			if importSpec.Name != nil && importSpec.Name.Name == "." {
				dotImportImportPath := strings.Trim(importSpec.Path.Value, `"`)
				dotImportPi := prog.AllPackages[prog.ImportMap[dotImportImportPath]]
				dotImports = append(dotImports, dotImportPi)
				findDotImports(prog, dotImportPi)
			}
		}
	}
}

func InlineDotImports(w io.Writer, importPath string) {
	/*imp2 := importer.New()
	imp2.Config.UseGcFallback = true
	cfg := types.Config{Import: imp2.Import}
	_ = cfg*/

	conf := loader.Config{
	//TypeChecker:   cfg,
	}

	conf.Import(importPath)

	prog, err := conf.Load()
	if err != nil {
		panic(err)
	}

	/*pi, err := imp.ImportPackage(importPath)
	if err != nil {
		panic(err)
	}
	_ = pi*/

	pi := prog.Imported[importPath]

	findDotImports(prog, pi)

	files := make(map[string]*ast.File)
	{
		// This package
		for _, file := range pi.Files {
			filename := prog.Fset.File(file.Package).Name()
			files[filename] = file
		}

		// All dot imports
		for _, pi := range dotImports {
			for _, file := range pi.Files {
				filename := prog.Fset.File(file.Package).Name()
				files[filename] = file
			}
		}
	}

	apkg := &ast.Package{Name: pi.Pkg.Name(), Files: files}

	merged := ast.MergePackageFiles(apkg, astMergeMode)

	WriteMergedPackage(w, prog.Fset, merged)
}

// WriteMergedPackage writes a merged package, typically coming from ast.MergePackageFiles, to w.
// It sorts and de-duplicates imports.
//
// TODO: Support comments.
func WriteMergedPackage(w io.Writer, fset *token.FileSet, merged *ast.File) {
	switch 3 {
	case 1:
		fmt.Fprintln(w, "package "+SprintAst(fset, merged.Name))
		fmt.Fprintln(w)
		fmt.Fprintln(w, `import (`)
		// TODO: SortImports (ala goimports).
		for _, importSpec := range merged.Imports {
			if importSpec.Name != nil && importSpec.Name.Name == "." {
				continue
			}
			fmt.Fprintln(w, "\t"+SprintAst(fset, importSpec))
		}
		fmt.Fprintln(w, `)`)
		fmt.Fprintln(w)

		for _, decl := range merged.Decls {
			if x, ok := decl.(*ast.GenDecl); ok && x.Tok == token.IMPORT {
				continue
			}

			fmt.Fprintln(w, SprintAst(fset, decl))
			fmt.Fprintln(w)
		}
	case 2:
		sortDecls(merged)

		//fmt.Fprintln(w, SprintAst(token.NewFileSet(), merged))

		//ast.SortImports(fset, merged)
		exp15.SortImports2(fset, merged)

		fmt.Fprintln(w, SprintAst(fset, merged))
	case 3:
		sortDecls(merged)

		// TODO: Clean up this mess...
		fset2, f2 := exp15.SortImports2(token.NewFileSet(), merged)

		fmt.Fprintln(w, "package "+SprintAst(fset, merged.Name))
		for _, decl := range f2.Decls {
			if x, ok := decl.(*ast.GenDecl); ok && x.Tok == token.IMPORT {
				fmt.Fprintln(w)
				fmt.Fprintln(w, SprintAst(fset2, decl))
			}
		}
		for _, decl := range merged.Decls {
			if x, ok := decl.(*ast.GenDecl); ok && (x.Tok == token.IMPORT || x.Tok == token.PACKAGE) {
				continue
			}

			fmt.Fprintln(w)
			fmt.Fprintln(w, SprintAst(fset, decl))
		}
	case 4:
		sortDecls(merged)

		src := []byte(SprintAst(fset, merged))

		out, err := imports.Process("", src, nil)
		if err != nil {
			panic(err)
		}
		os.Stdout.Write(out)
		fmt.Println()
	}
}

func sortDecls(merged *ast.File) {
	var sortedDecls []ast.Decl
	for _, decl := range merged.Decls {
		if x, ok := decl.(*ast.GenDecl); ok && x.Tok == token.PACKAGE {
			sortedDecls = append(sortedDecls, decl)
		}
	}
	/*for _, decl := range merged.Decls {
		if x, ok := decl.(*ast.GenDecl); ok && x.Tok == token.IMPORT {
			sortedDecls = append(sortedDecls, decl)
			goon.DumpExpr(decl)
		}
	}*/
	var specs []ast.Spec
	for _, importSpec := range merged.Imports {
		if importSpec.Name != nil && importSpec.Name.Name == "." {
			continue
		}
		importSpec.EndPos = 0
		specs = append(specs, importSpec)
	}
	sortedDecls = append(sortedDecls, &ast.GenDecl{
		Tok:    token.IMPORT,
		Lparen: (token.Pos)(1), // Needs to be non-zero to be considered as a group.
		Specs:  specs,
	})
	//goon.DumpExpr(sortedDecls[len(sortedDecls)-1])
	for _, decl := range merged.Decls {
		if x, ok := decl.(*ast.GenDecl); ok && (x.Tok == token.IMPORT || x.Tok == token.PACKAGE) {
			continue
		}
		sortedDecls = append(sortedDecls, decl)
	}
	merged.Decls = sortedDecls
}
<commit_msg>Update to upstream API change.<commit_after>// Package exp11 displays Go package source code with dot imports inlined.
package exp11

import (
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"io"
	"os"
	"strings"

	"golang.org/x/tools/go/loader"
	"golang.org/x/tools/imports"

	//"golang.org/x/tools/go/types"
	//"honnef.co/go/importer"

	. "github.com/shurcooL/go/gists/gist5504644"
	. "github.com/shurcooL/go/gists/gist5639599"

	"github.com/shurcooL/go/exp/15"
)

var _ = AstPackageFromBuildPackage
var _ = PrintlnAst
var _ = exp15.SortImports

const parserMode = parser.ParseComments
const astMergeMode = 0*ast.FilterFuncDuplicates | ast.FilterUnassociatedComments | ast.FilterImportDuplicates

var dotImports []*loader.PackageInfo

func findDotImports(prog *loader.Program, pi *loader.PackageInfo) {
	for _, file := range pi.Files {
		for _, importSpec := range file.Imports {
			if importSpec.Name != nil && importSpec.Name.Name == "." {
				dotImportImportPath := strings.Trim(importSpec.Path.Value, `"`)
				dotImportPi := prog.Package(dotImportImportPath)
				dotImports = append(dotImports, dotImportPi)
				findDotImports(prog, dotImportPi)
			}
		}
	}
}

func InlineDotImports(w io.Writer, importPath string) {
	/*imp2 := importer.New()
	imp2.Config.UseGcFallback = true
	cfg := types.Config{Import: imp2.Import}
	_ = cfg*/

	conf := loader.Config{
	//TypeChecker:   cfg,
	}

	conf.Import(importPath)

	prog, err := conf.Load()
	if err != nil {
		panic(err)
	}

	/*pi, err := imp.ImportPackage(importPath)
	if err != nil {
		panic(err)
	}
	_ = pi*/

	pi := prog.Imported[importPath]

	findDotImports(prog, pi)

	files := make(map[string]*ast.File)
	{
		// This package
		for _, file := range pi.Files {
			filename := prog.Fset.File(file.Package).Name()
			files[filename] = file
		}

		// All dot imports
		for _, pi := range dotImports {
			for _, file := range pi.Files {
				filename := prog.Fset.File(file.Package).Name()
				files[filename] = file
			}
		}
	}

	apkg := &ast.Package{Name: pi.Pkg.Name(), Files: files}

	merged := ast.MergePackageFiles(apkg, astMergeMode)

	WriteMergedPackage(w, prog.Fset, merged)
}

// WriteMergedPackage writes a merged package, typically coming from ast.MergePackageFiles, to w.
// It sorts and de-duplicates imports.
//
// TODO: Support comments.
func WriteMergedPackage(w io.Writer, fset *token.FileSet, merged *ast.File) {
	switch 3 {
	case 1:
		fmt.Fprintln(w, "package "+SprintAst(fset, merged.Name))
		fmt.Fprintln(w)
		fmt.Fprintln(w, `import (`)
		// TODO: SortImports (ala goimports).
		for _, importSpec := range merged.Imports {
			if importSpec.Name != nil && importSpec.Name.Name == "." {
				continue
			}
			fmt.Fprintln(w, "\t"+SprintAst(fset, importSpec))
		}
		fmt.Fprintln(w, `)`)
		fmt.Fprintln(w)

		for _, decl := range merged.Decls {
			if x, ok := decl.(*ast.GenDecl); ok && x.Tok == token.IMPORT {
				continue
			}

			fmt.Fprintln(w, SprintAst(fset, decl))
			fmt.Fprintln(w)
		}
	case 2:
		sortDecls(merged)

		//fmt.Fprintln(w, SprintAst(token.NewFileSet(), merged))

		//ast.SortImports(fset, merged)
		exp15.SortImports2(fset, merged)

		fmt.Fprintln(w, SprintAst(fset, merged))
	case 3:
		sortDecls(merged)

		// TODO: Clean up this mess...
		fset2, f2 := exp15.SortImports2(token.NewFileSet(), merged)

		fmt.Fprintln(w, "package "+SprintAst(fset, merged.Name))
		for _, decl := range f2.Decls {
			if x, ok := decl.(*ast.GenDecl); ok && x.Tok == token.IMPORT {
				fmt.Fprintln(w)
				fmt.Fprintln(w, SprintAst(fset2, decl))
			}
		}
		for _, decl := range merged.Decls {
			if x, ok := decl.(*ast.GenDecl); ok && (x.Tok == token.IMPORT || x.Tok == token.PACKAGE) {
				continue
			}

			fmt.Fprintln(w)
			fmt.Fprintln(w, SprintAst(fset, decl))
		}
	case 4:
		sortDecls(merged)

		src := []byte(SprintAst(fset, merged))

		out, err := imports.Process("", src, nil)
		if err != nil {
			panic(err)
		}
		os.Stdout.Write(out)
		fmt.Println()
	}
}

func sortDecls(merged *ast.File) {
	var sortedDecls []ast.Decl
	for _, decl := range merged.Decls {
		if x, ok := decl.(*ast.GenDecl); ok && x.Tok == token.PACKAGE {
			sortedDecls = append(sortedDecls, decl)
		}
	}
	/*for _, decl := range merged.Decls {
		if x, ok := decl.(*ast.GenDecl); ok && x.Tok == token.IMPORT {
			sortedDecls = append(sortedDecls, decl)
			goon.DumpExpr(decl)
		}
	}*/
	var specs []ast.Spec
	for _, importSpec := range merged.Imports {
		if importSpec.Name != nil && importSpec.Name.Name == "." {
			continue
		}
		importSpec.EndPos = 0
		specs = append(specs, importSpec)
	}
	sortedDecls = append(sortedDecls, &ast.GenDecl{
		Tok:    token.IMPORT,
		Lparen: (token.Pos)(1), // Needs to be non-zero to be considered as a group.
		Specs:  specs,
	})
	//goon.DumpExpr(sortedDecls[len(sortedDecls)-1])
	for _, decl := range merged.Decls {
		if x, ok := decl.(*ast.GenDecl); ok && (x.Tok == token.IMPORT || x.Tok == token.PACKAGE) {
			continue
		}
		sortedDecls = append(sortedDecls, decl)
	}
	merged.Decls = sortedDecls
}
<|endoftext|>


<commit_before>package exp12

import (
	"github.com/shurcooL/go/exp/13"
	"github.com/shurcooL/go/vcs"

	. "gist.github.com/7802150.git"
)

// TODO: Rename to "Folder" or "FileSystemNode" or something.
type MaybeVcsRepo struct {
	path string

	VcsState *exp13.VcsState

	DepNode2
}

func (this *MaybeVcsRepo) Update() {
	//this.Vcs = vcs.New(this.path)

	if vcs := vcs.New(this.path); vcs != nil {
		if vcsState, ok := vcsStates[vcs.RootPath()]; ok {
			this.VcsState = vcsState
		} else {
			this.VcsState = exp13.NewVcsState(vcs)
			vcsStates[vcs.RootPath()] = this.VcsState
		}
	}
}

func NewMaybeVcsRepo(path string) *MaybeVcsRepo {
	this := &MaybeVcsRepo{path: path}
	// No DepNode2I sources, so each instance can only be updated (i.e. initialized) once
	return this
}

// =====

// TODO: Use FileUri or similar instead of string for clean path to repo root.
// rootPath -> *VcsState
var vcsStates = make(map[string]*exp13.VcsState)
<commit_msg>Rename MaybeVcsRepo to Directory.<commit_after>package exp12

import (
	"github.com/shurcooL/go/exp/13"
	"github.com/shurcooL/go/vcs"

	. "gist.github.com/7802150.git"
)

// TODO: Use FileUri or similar type instead of string for clean path to repo root.
// rootPath -> *VcsState
var repos = make(map[string]*exp13.VcsState)

type Directory struct {
	path string

	Repo *exp13.VcsState

	DepNode2
}

func (this *Directory) Update() {
	if vcs := vcs.New(this.path); vcs != nil {
		if repo, ok := repos[vcs.RootPath()]; ok {
			this.Repo = repo
		} else {
			this.Repo = exp13.NewVcsState(vcs)
			repos[vcs.RootPath()] = this.Repo
		}
	}
}

func NewDirectory(path string) *Directory {
	this := &Directory{path: path}
	// No DepNode2I sources, so each instance can only be updated (i.e. initialized) once
	return this
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"flag"
	"io"
	"log"
	"os"

	"github.com/moby/buildkit/client/llb"
	"github.com/moby/buildkit/client/llb/imagemetaresolver"
	"github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb"
	"github.com/moby/buildkit/solver/pb"
	"github.com/moby/buildkit/util/appcontext"
)

type buildOpt struct {
	target string
}

func main() {
	var opt buildOpt
	flag.StringVar(&opt.target, "target", "", "target stage")
	flag.Parse()

	df, err := io.ReadAll(os.Stdin)
	if err != nil {
		panic(err)
	}

	caps := pb.Caps.CapSet(pb.Caps.All())

	state, img, bi, err := dockerfile2llb.Dockerfile2LLB(appcontext.Context(), df, dockerfile2llb.ConvertOpt{
		MetaResolver: imagemetaresolver.Default(),
		Target:       opt.target,
		LLBCaps:      &caps,
	})
	if err != nil {
		log.Printf("err: %+v", err)
		panic(err)
	}

	_ = img
	_ = bi

	dt, err := state.Marshal(context.TODO())
	if err != nil {
		panic(err)
	}
	llb.WriteTo(dt, os.Stdout)
}
<commit_msg>examples/dockerfile2llb: improve error handling<commit_after>package main

import (
	"context"
	"flag"
	"io"
	"os"

	"github.com/moby/buildkit/client/llb"
	"github.com/moby/buildkit/client/llb/imagemetaresolver"
	"github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb"
	"github.com/moby/buildkit/solver/pb"
	"github.com/moby/buildkit/util/appcontext"
	"github.com/sirupsen/logrus"
)

type buildOpt struct {
	target string
}

func main() {
	if err := xmain(); err != nil {
		logrus.Fatal(err)
	}
}

func xmain() error {
	var opt buildOpt
	flag.StringVar(&opt.target, "target", "", "target stage")
	flag.Parse()

	df, err := io.ReadAll(os.Stdin)
	if err != nil {
		return err
	}

	caps := pb.Caps.CapSet(pb.Caps.All())

	state, img, bi, err := dockerfile2llb.Dockerfile2LLB(appcontext.Context(), df, dockerfile2llb.ConvertOpt{
		MetaResolver: imagemetaresolver.Default(),
		Target:       opt.target,
		LLBCaps:      &caps,
	})
	if err != nil {
		return err
	}

	_ = img
	_ = bi

	dt, err := state.Marshal(context.TODO())
	if err != nil {
		return err
	}
	return llb.WriteTo(dt, os.Stdout)
}
<|endoftext|>


<commit_before>// Code generated by 'go generate'
// source: fmts/gendoc.go
// DO NOT EDIT!
// Please run '$ go generate ./...' instead to update this file

// Package fmts holds defined errorformats.
//
// Defined formats:
//
// 	ansible
// 		ansible-lint	(ansible-lint -p playbook.yml) Checks playbooks for practices and behaviour that could potentially be improved - https://github.com/ansible/ansible-lint
// 	css
// 		stylelint	A mighty modern CSS linter - https://github.com/stylelint/stylelint
// 	env
// 		dotenv-linter	Linter for .env files - https://github.com/mgrachev/dotenv-linter
// 	go
// 		go-consistent	Source code analyzer that helps you to make your Go programs more consistent - https://github.com/quasilyte/go-consistent
// 		golangci-lint	(golangci-lint run --out-format=line-number) GolangCI-Lint is a linters aggregator. - https://github.com/golangci/golangci-lint
// 		golint	linter for Go source code - https://github.com/golang/lint
// 		govet	Vet examines Go source code and reports suspicious problems - https://golang.org/cmd/vet/
// 	haml
// 		haml-lint	Tool for writing clean and consistent HAML - https://github.com/sds/haml-lint
// 	javascript
// 		eslint	(eslint [-f stylish]) A fully pluggable tool for identifying and reporting on patterns in JavaScript - https://github.com/eslint/eslint
// 		eslint-compact	(eslint -f compact) A fully pluggable tool for identifying and reporting on patterns in JavaScript - https://github.com/eslint/eslint
// 	php
// 		phpstan	(phpstan --error-format=raw) PHP Static Analysis Tool - discover bugs in your code without running it! - https://github.com/phpstan/phpstan
// 	puppet
// 		puppet-lint	Check that your Puppet manifests conform to the style guide - https://github.com/rodjek/puppet-lint
// 	python
// 		pep8	Python style guide checker - https://pypi.python.org/pypi/pep8
// 	ruby
// 		brakeman	(brakeman --quiet --format tabs) A static analysis security vulnerability scanner for Ruby on Rails applications - https://github.com/presidentbeef/brakeman
// 		fasterer	Speed improvements suggester - https://github.com/DamirSvrtan/fasterer
// 		reek	(reek --single-line) Code smell detector for Ruby - https://github.com/troessner/reek
// 		rubocop	A Ruby static code analyzer, based on the community Ruby style guide - https://github.com/rubocop-hq/rubocop
// 	rust
// 		cargo-check	(cargo check -q --message-format=short) Check a local package and all of its dependencies for errors - https://github.com/rust-lang/cargo
// 		clippy	(cargo clippy -q --message-format=short) A bunch of lints to catch common mistakes and improve your Rust code - https://github.com/rust-lang/rust-clippy
// 	scala
// 		sbt	the interactive build tool - http://www.scala-sbt.org/
// 		sbt-scalastyle	Scalastyle - SBT plugin - http://www.scalastyle.org/sbt.html
// 		scalac	Scala compiler - http://www.scala-lang.org/
// 		scalastyle	Scalastyle - Command line - http://www.scalastyle.org/command-line.html
// 	typescript
// 		tsc	TypeScript compiler - https://www.typescriptlang.org/
// 		tslint	An extensible linter for the TypeScript language - https://github.com/palantir/tslint
package fmts
<commit_msg>Update docs<commit_after>// Code generated by 'go generate'
// source: fmts/gendoc.go
// DO NOT EDIT!
// Please run '$ go generate ./...' instead to update this file

// Package fmts holds defined errorformats.
//
// Defined formats:
//
// 	ansible
// 		ansible-lint	(ansible-lint -p playbook.yml) Checks playbooks for practices and behaviour that could potentially be improved - https://github.com/ansible/ansible-lint
// 	css
// 		stylelint	A mighty modern CSS linter - https://github.com/stylelint/stylelint
// 	env
// 		dotenv-linter	Linter for .env files - https://github.com/mgrachev/dotenv-linter
// 	go
// 		go-consistent	Source code analyzer that helps you to make your Go programs more consistent - https://github.com/quasilyte/go-consistent
// 		golangci-lint	(golangci-lint run --out-format=line-number) GolangCI-Lint is a linters aggregator. - https://github.com/golangci/golangci-lint
// 		golint	linter for Go source code - https://github.com/golang/lint
// 		govet	Vet examines Go source code and reports suspicious problems - https://golang.org/cmd/vet/
// 	haml
// 		haml-lint	Tool for writing clean and consistent HAML - https://github.com/sds/haml-lint
// 	javascript
// 		eslint	(eslint [-f stylish]) A fully pluggable tool for identifying and reporting on patterns in JavaScript - https://github.com/eslint/eslint
// 		eslint-compact	(eslint -f compact) A fully pluggable tool for identifying and reporting on patterns in JavaScript - https://github.com/eslint/eslint
// 		standardjs	(standard) JavaScript style guide, linter, and formatter - https://github.com/standard/standard
// 	php
// 		phpstan	(phpstan --error-format=raw) PHP Static Analysis Tool - discover bugs in your code without running it! - https://github.com/phpstan/phpstan
// 	puppet
// 		puppet-lint	Check that your Puppet manifests conform to the style guide - https://github.com/rodjek/puppet-lint
// 	python
// 		pep8	Python style guide checker - https://pypi.python.org/pypi/pep8
// 	ruby
// 		brakeman	(brakeman --quiet --format tabs) A static analysis security vulnerability scanner for Ruby on Rails applications - https://github.com/presidentbeef/brakeman
// 		fasterer	Speed improvements suggester - https://github.com/DamirSvrtan/fasterer
// 		reek	(reek --single-line) Code smell detector for Ruby - https://github.com/troessner/reek
// 		rubocop	A Ruby static code analyzer, based on the community Ruby style guide - https://github.com/rubocop-hq/rubocop
// 	rust
// 		cargo-check	(cargo check -q --message-format=short) Check a local package and all of its dependencies for errors - https://github.com/rust-lang/cargo
// 		clippy	(cargo clippy -q --message-format=short) A bunch of lints to catch common mistakes and improve your Rust code - https://github.com/rust-lang/rust-clippy
// 	scala
// 		sbt	the interactive build tool - http://www.scala-sbt.org/
// 		sbt-scalastyle	Scalastyle - SBT plugin - http://www.scalastyle.org/sbt.html
// 		scalac	Scala compiler - http://www.scala-lang.org/
// 		scalastyle	Scalastyle - Command line - http://www.scalastyle.org/command-line.html
// 	typescript
// 		tsc	TypeScript compiler - https://www.typescriptlang.org/
// 		tslint	An extensible linter for the TypeScript language - https://github.com/palantir/tslint
package fmts
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"github.com/veandco/go-sdl2/sdl"
	"github.com/veandco/go-sdl2/ttf"
)

var winTitle string = "Text"
var winWidth, winHeight int32 = 800, 600

func run() int {
	var window *sdl.Window
	var font *ttf.Font
	var surface *sdl.Surface
	var solid *sdl.Surface
	var err error

	sdl.Init(sdl.INIT_VIDEO)

	if err := ttf.Init(); err != nil {
		fmt.Fprintf(os.Stderr, "Failed to initialize TTF: %s\n", err)
		return 1
	}

	if window, err = sdl.CreateWindow(winTitle, sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, winWidth, winHeight, sdl.WINDOW_SHOWN); err != nil {
		fmt.Fprintf(os.Stderr, "Failed to create window: %s\n", err)
		return 2
	}
	defer window.Destroy()

	if font, err = ttf.OpenFont("../../assets/test.ttf", 32); err != nil {
		fmt.Fprint(os.Stderr, "Failed to open font: %s\n", err)
		return 4
	}
	defer font.Close()

	if solid, err = font.RenderUTF8_Solid("Hello, World!", sdl.Color{255, 0, 0, 255}); err != nil {
		fmt.Fprint(os.Stderr, "Failed to render text: %s\n", err)
		return 5
	}
	defer solid.Free()

	if surface, err = window.GetSurface(); err != nil {
		fmt.Fprint(os.Stderr, "Failed to get window surface: %s\n", err)
		return 6
	}

	if err = solid.Blit(nil, surface, nil); err != nil {
		fmt.Fprint(os.Stderr, "Failed to put text on window surface: %s\n", err)
		return 7
	}

	// Show the pixels for a while
	window.UpdateSurface()
	sdl.Delay(3000)

	return 0
}

func main() {
	os.Exit(run())
}
<commit_msg>examples: text: text.go: Update API<commit_after>package main

import (
	"fmt"
	"os"

	"github.com/veandco/go-sdl2/sdl"
	"github.com/veandco/go-sdl2/ttf"
)

var winTitle string = "Text"
var winWidth, winHeight int32 = 800, 600

func run() int {
	var window *sdl.Window
	var font *ttf.Font
	var surface *sdl.Surface
	var solid *sdl.Surface
	var err error

	sdl.Init(sdl.INIT_VIDEO)

	if err := ttf.Init(); err != nil {
		fmt.Fprintf(os.Stderr, "Failed to initialize TTF: %s\n", err)
		return 1
	}

	if window, err = sdl.CreateWindow(winTitle, sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, winWidth, winHeight, sdl.WINDOW_SHOWN); err != nil {
		fmt.Fprintf(os.Stderr, "Failed to create window: %s\n", err)
		return 2
	}
	defer window.Destroy()

	if font, err = ttf.OpenFont("../../assets/test.ttf", 32); err != nil {
		fmt.Fprint(os.Stderr, "Failed to open font: %s\n", err)
		return 4
	}
	defer font.Close()

	if solid, err = font.RenderUTF8Solid("Hello, World!", sdl.Color{255, 0, 0, 255}); err != nil {
		fmt.Fprint(os.Stderr, "Failed to render text: %s\n", err)
		return 5
	}
	defer solid.Free()

	if surface, err = window.GetSurface(); err != nil {
		fmt.Fprint(os.Stderr, "Failed to get window surface: %s\n", err)
		return 6
	}

	if err = solid.Blit(nil, surface, nil); err != nil {
		fmt.Fprint(os.Stderr, "Failed to put text on window surface: %s\n", err)
		return 7
	}

	// Show the pixels for a while
	window.UpdateSurface()
	sdl.Delay(3000)

	return 0
}

func main() {
	os.Exit(run())
}
<|endoftext|>


<commit_before>package user

import (
	"github.com/hackform/governor"
	"github.com/hackform/governor/service/user/model"
	"github.com/hackform/governor/service/user/session"
	"github.com/hackform/governor/service/user/token"
	"github.com/hackform/governor/util/uid"
	"github.com/labstack/echo"
	"github.com/sirupsen/logrus"
	"net/http"
	"strings"
	"time"
)

type (
	reqUserAuth struct {
		Username     string `json:"username"`
		Password     string `json:"password"`
		RefreshToken string `json:"refresh_token"`
	}

	reqExchangeToken struct {
		RefreshToken string `json:"refresh_token"`
	}

	resUserAuth struct {
		Valid        bool          `json:"valid"`
		AccessToken  string        `json:"access_token,omitempty"`
		RefreshToken string        `json:"refresh_token,omitempty"`
		Claims       *token.Claims `json:"claims,omitempty"`
		Username     string        `json:"username,omitempty"`
		FirstName    string        `json:"first_name,omitempty"`
		LastName     string        `json:"last_name,omitempty"`
	}
)

func (r *reqUserAuth) valid() *governor.Error {
	if err := hasUsername(r.Username); err != nil {
		return err
	}
	if err := hasPassword(r.Password); err != nil {
		return err
	}
	return nil
}

func (r *reqExchangeToken) valid() *governor.Error {
	if err := hasToken(r.RefreshToken); err != nil {
		return err
	}
	return nil
}

const (
	authenticationSubject = "authentication"
	refreshSubject        = "refresh"
)

func (u *User) mountAuth(conf governor.Config, r *echo.Group, l *logrus.Logger) error {
	db := u.db.DB()
	ch := u.cache.Cache()
	mailer := u.mailer

	r.POST("/login", func(c echo.Context) error {
		ruser := &reqUserAuth{}
		if err := c.Bind(ruser); err != nil {
			return governor.NewErrorUser(moduleIDAuth, err.Error(), 0, http.StatusBadRequest)
		}
		if err := ruser.valid(); err != nil {
			return err
		}

		m, err := usermodel.GetByUsername(db, ruser.Username)
		if err != nil {
			if err.Code() == 2 {
				err.SetErrorUser()
			}
			return err
		}
		if m.ValidatePass(ruser.Password) {
			sessionID := ""
			// if session_id is provided, is in cache, and is valid, set it as the sessionID
			if ok, claims := u.tokenizer.GetClaims(ruser.RefreshToken); ok {
				if s := strings.Split(claims.Id, ":"); len(s) == 2 {
					if _, err := ch.Get(s[0]).Result(); err == nil {
						if id, err := uid.FromBase64(4, 8, 4, s[0]); err == nil {
							sessionID = id.Base64()
						}
					}
				}
			}

			var s *session.Session
			if sessionID == "" {
				// otherwise, create a new sessionID
				if s, err = session.New(m, c); err != nil {
					err.AddTrace(moduleIDAuth)
					return err
				}
			} else {
				if s, err = session.FromSessionID(sessionID, m, c); err != nil {
					err.AddTrace(moduleIDAuth)
					return err
				}
			}

			// generate an access token
			accessToken, claims, err := u.tokenizer.Generate(m, u.accessTime, authenticationSubject, "")
			if err != nil {
				err.AddTrace(moduleIDAuth)
				return err
			}
			// generate a refresh tokens with the sessionKey
			refreshToken, _, err := u.tokenizer.Generate(m, u.refreshTime, refreshSubject, s.SessionID+":"+s.SessionKey)
			if err != nil {
				err.AddTrace(moduleIDAuth)
				return err
			}

			// store the session in cache
			if isMember, err := ch.HExists(s.UserKey(), s.SessionID).Result(); err == nil {
				sessionGob, err := s.ToGob()
				if err != nil {
					err.AddTrace(moduleIDAuth)
					return err
				}
				if !isMember {
					if err := mailer.Send(m.Email, "New Login", "New login from "+s.IP+" with the useragent: "+s.UserAgent); err != nil {
						err.AddTrace(moduleIDAuth)
						return err
					}
				}
				if err := ch.HSet(s.UserKey(), s.SessionID, sessionGob).Err(); err != nil {
					return governor.NewError(moduleIDAuth, err.Error(), 0, http.StatusInternalServerError)
				}
			} else {
				return governor.NewError(moduleIDAuth, err.Error(), 0, http.StatusInternalServerError)
			}

			// set the session id and key into cache
			if err := ch.Set(s.SessionID, s.SessionKey, time.Duration(u.refreshTime*b1)).Err(); err != nil {
				return governor.NewError(moduleIDAuth, err.Error(), 0, http.StatusInternalServerError)
			}

			return c.JSON(http.StatusOK, &resUserAuth{
				Valid:        true,
				AccessToken:  accessToken,
				RefreshToken: refreshToken,
				Claims:       claims,
				Username:     m.Username,
				FirstName:    m.FirstName,
				LastName:     m.LastName,
			})
		}

		return c.JSON(http.StatusUnauthorized, &resUserAuth{
			Valid: false,
		})
	})

	r.POST("/exchange", func(c echo.Context) error {
		ruser := &reqExchangeToken{}
		if err := c.Bind(ruser); err != nil {
			return governor.NewErrorUser(moduleIDAuth, err.Error(), 0, http.StatusBadRequest)
		}
		if err := ruser.valid(); err != nil {
			return err
		}

		sessionID := ""
		sessionKey := ""
		if ok, claims := u.tokenizer.GetClaims(ruser.RefreshToken); ok {
			if s := strings.Split(claims.Id, ":"); len(s) == 2 {
				if key, err := ch.Get(s[0]).Result(); err == nil {
					sessionID = s[0]
					sessionKey = key
				}
			}
		}

		if sessionID == "" {
			return governor.NewErrorUser(moduleIDAuth, "malformed refresh token", 0, http.StatusUnauthorized)
		}

		// check the refresh token
		validToken, claims := u.tokenizer.Validate(ruser.RefreshToken, refreshSubject, sessionID+":"+sessionKey)
		if !validToken {
			return c.JSON(http.StatusUnauthorized, &resUserAuth{
				Valid: false,
			})
		}

		// generate a new accessToken from the refreshToken claims
		accessToken, err := u.tokenizer.GenerateFromClaims(claims, u.accessTime, authenticationSubject, "")
		if err != nil {
			err.AddTrace(moduleIDAuth)
			return err
		}

		return c.JSON(http.StatusOK, &resUserAuth{
			Valid:       true,
			AccessToken: accessToken,
			Claims:      claims,
		})
	})

	r.POST("/refresh", func(c echo.Context) error {
		ruser := &reqExchangeToken{}
		if err := c.Bind(ruser); err != nil {
			return governor.NewErrorUser(moduleIDAuth, err.Error(), 0, http.StatusBadRequest)
		}
		if err := ruser.valid(); err != nil {
			return err
		}

		sessionID := ""
		sessionKey := ""
		if ok, claims := u.tokenizer.GetClaims(ruser.RefreshToken); ok {
			if s := strings.Split(claims.Id, ":"); len(s) == 2 {
				if key, err := ch.Get(s[0]).Result(); err == nil {
					sessionID = s[0]
					sessionKey = key
				}
			}
		}

		if sessionID == "" {
			return governor.NewErrorUser(moduleIDAuth, "malformed refresh token", 0, http.StatusUnauthorized)
		}

		// check the refresh token
		validToken, claims := u.tokenizer.Validate(ruser.RefreshToken, refreshSubject, sessionID+":"+sessionKey)
		if !validToken {
			return c.JSON(http.StatusUnauthorized, &resUserAuth{
				Valid: false,
			})
		}

		// create a new key for the session
		key, err := uid.NewU(0, 16)
		if err != nil {
			err.AddTrace(moduleIDAuth)
			return err
		}
		sessionKey = key.Base64()

		// generate a new refreshToken from the refreshToken claims
		refreshToken, err := u.tokenizer.GenerateFromClaims(claims, u.accessTime, refreshSubject, sessionID+":"+sessionKey)
		if err != nil {
			err.AddTrace(moduleIDAuth)
			return err
		}

		// set the session id and key into cache
		if err := ch.Set(sessionID, sessionKey, time.Duration(u.refreshTime*b1)).Err(); err != nil {
			return governor.NewError(moduleIDAuth, err.Error(), 0, http.StatusInternalServerError)
		}

		return c.JSON(http.StatusOK, &resUserAuth{
			Valid:        true,
			RefreshToken: refreshToken,
		})
	})

	if conf.IsDebug() {
		r.GET("/decode", func(c echo.Context) error {
			return c.JSON(http.StatusOK, resUserAuth{
				Valid:  true,
				Claims: c.Get("user").(*token.Claims),
			})
		}, u.gate.User())
	}

	return nil
}
<commit_msg>login now sets cookies<commit_after>package user

import (
	"github.com/hackform/governor"
	"github.com/hackform/governor/service/user/model"
	"github.com/hackform/governor/service/user/session"
	"github.com/hackform/governor/service/user/token"
	"github.com/hackform/governor/util/uid"
	"github.com/labstack/echo"
	"github.com/sirupsen/logrus"
	"net/http"
	"strings"
	"time"
)

type (
	reqUserAuth struct {
		Username     string `json:"username"`
		Password     string `json:"password"`
		RefreshToken string `json:"refresh_token"`
	}

	reqExchangeToken struct {
		RefreshToken string `json:"refresh_token"`
	}

	resUserAuth struct {
		Valid        bool          `json:"valid"`
		AccessToken  string        `json:"access_token,omitempty"`
		RefreshToken string        `json:"refresh_token,omitempty"`
		Claims       *token.Claims `json:"claims,omitempty"`
		Username     string        `json:"username,omitempty"`
		FirstName    string        `json:"first_name,omitempty"`
		LastName     string        `json:"last_name,omitempty"`
	}
)

func (r *reqUserAuth) valid() *governor.Error {
	if err := hasUsername(r.Username); err != nil {
		return err
	}
	if err := hasPassword(r.Password); err != nil {
		return err
	}
	return nil
}

func (r *reqExchangeToken) valid() *governor.Error {
	if err := hasToken(r.RefreshToken); err != nil {
		return err
	}
	return nil
}

const (
	authenticationSubject = "authentication"
	refreshSubject        = "refresh"
)

var (
	userAuthGroup = ""
)

func (u *User) mountAuth(conf governor.Config, r *echo.Group, l *logrus.Logger) error {
	db := u.db.DB()
	ch := u.cache.Cache()
	mailer := u.mailer

	userAuthGroup = conf.BaseURL + "/u/auth"

	r.POST("/login", func(c echo.Context) error {
		ruser := &reqUserAuth{}
		if err := c.Bind(ruser); err != nil {
			return governor.NewErrorUser(moduleIDAuth, err.Error(), 0, http.StatusBadRequest)
		}
		if err := ruser.valid(); err != nil {
			return err
		}

		m, err := usermodel.GetByUsername(db, ruser.Username)
		if err != nil {
			if err.Code() == 2 {
				err.SetErrorUser()
			}
			return err
		}
		if m.ValidatePass(ruser.Password) {
			sessionID := ""
			// if session_id is provided, is in cache, and is valid, set it as the sessionID
			if ok, claims := u.tokenizer.GetClaims(ruser.RefreshToken); ok {
				if s := strings.Split(claims.Id, ":"); len(s) == 2 {
					if _, err := ch.Get(s[0]).Result(); err == nil {
						if id, err := uid.FromBase64(4, 8, 4, s[0]); err == nil {
							sessionID = id.Base64()
						}
					}
				}
			}

			var s *session.Session
			if sessionID == "" {
				// otherwise, create a new sessionID
				if s, err = session.New(m, c); err != nil {
					err.AddTrace(moduleIDAuth)
					return err
				}
			} else {
				if s, err = session.FromSessionID(sessionID, m, c); err != nil {
					err.AddTrace(moduleIDAuth)
					return err
				}
			}

			// generate an access token
			accessToken, claims, err := u.tokenizer.Generate(m, u.accessTime, authenticationSubject, "")
			if err != nil {
				err.AddTrace(moduleIDAuth)
				return err
			}
			// generate a refresh tokens with the sessionKey
			refreshToken, _, err := u.tokenizer.Generate(m, u.refreshTime, refreshSubject, s.SessionID+":"+s.SessionKey)
			if err != nil {
				err.AddTrace(moduleIDAuth)
				return err
			}

			// store the session in cache
			if isMember, err := ch.HExists(s.UserKey(), s.SessionID).Result(); err == nil {
				sessionGob, err := s.ToGob()
				if err != nil {
					err.AddTrace(moduleIDAuth)
					return err
				}
				if !isMember {
					if err := mailer.Send(m.Email, "New Login", "New login from "+s.IP+" with the useragent: "+s.UserAgent); err != nil {
						err.AddTrace(moduleIDAuth)
						return err
					}
				}
				if err := ch.HSet(s.UserKey(), s.SessionID, sessionGob).Err(); err != nil {
					return governor.NewError(moduleIDAuth, err.Error(), 0, http.StatusInternalServerError)
				}
			} else {
				return governor.NewError(moduleIDAuth, err.Error(), 0, http.StatusInternalServerError)
			}

			// set the session id and key into cache
			if err := ch.Set(s.SessionID, s.SessionKey, time.Duration(u.refreshTime*b1)).Err(); err != nil {
				return governor.NewError(moduleIDAuth, err.Error(), 0, http.StatusInternalServerError)
			}

			accessCookie := &http.Cookie{
				Name:     "access_token",
				Value:    accessToken,
				Path:     conf.BaseURL,
				Expires:  time.Now().Add(time.Duration(u.accessTime * b1)),
				HttpOnly: true,
			}
			refreshCookie := &http.Cookie{
				Name:     "refresh_token",
				Value:    refreshToken,
				Path:     userAuthGroup,
				Expires:  time.Now().Add(time.Duration(u.refreshTime * b1)),
				HttpOnly: true,
			}

			c.SetCookie(accessCookie)
			c.SetCookie(refreshCookie)

			return c.JSON(http.StatusOK, &resUserAuth{
				Valid:        true,
				AccessToken:  accessToken,
				RefreshToken: refreshToken,
				Claims:       claims,
				Username:     m.Username,
				FirstName:    m.FirstName,
				LastName:     m.LastName,
			})
		}

		return c.JSON(http.StatusUnauthorized, &resUserAuth{
			Valid: false,
		})
	})

	r.POST("/exchange", func(c echo.Context) error {
		ruser := &reqExchangeToken{}
		if err := c.Bind(ruser); err != nil {
			return governor.NewErrorUser(moduleIDAuth, err.Error(), 0, http.StatusBadRequest)
		}
		if err := ruser.valid(); err != nil {
			return err
		}

		sessionID := ""
		sessionKey := ""
		if ok, claims := u.tokenizer.GetClaims(ruser.RefreshToken); ok {
			if s := strings.Split(claims.Id, ":"); len(s) == 2 {
				if key, err := ch.Get(s[0]).Result(); err == nil {
					sessionID = s[0]
					sessionKey = key
				}
			}
		}

		if sessionID == "" {
			return governor.NewErrorUser(moduleIDAuth, "malformed refresh token", 0, http.StatusUnauthorized)
		}

		// check the refresh token
		validToken, claims := u.tokenizer.Validate(ruser.RefreshToken, refreshSubject, sessionID+":"+sessionKey)
		if !validToken {
			return c.JSON(http.StatusUnauthorized, &resUserAuth{
				Valid: false,
			})
		}

		// generate a new accessToken from the refreshToken claims
		accessToken, err := u.tokenizer.GenerateFromClaims(claims, u.accessTime, authenticationSubject, "")
		if err != nil {
			err.AddTrace(moduleIDAuth)
			return err
		}

		return c.JSON(http.StatusOK, &resUserAuth{
			Valid:       true,
			AccessToken: accessToken,
			Claims:      claims,
		})
	})

	r.POST("/refresh", func(c echo.Context) error {
		ruser := &reqExchangeToken{}
		if err := c.Bind(ruser); err != nil {
			return governor.NewErrorUser(moduleIDAuth, err.Error(), 0, http.StatusBadRequest)
		}
		if err := ruser.valid(); err != nil {
			return err
		}

		sessionID := ""
		sessionKey := ""
		if ok, claims := u.tokenizer.GetClaims(ruser.RefreshToken); ok {
			if s := strings.Split(claims.Id, ":"); len(s) == 2 {
				if key, err := ch.Get(s[0]).Result(); err == nil {
					sessionID = s[0]
					sessionKey = key
				}
			}
		}

		if sessionID == "" {
			return governor.NewErrorUser(moduleIDAuth, "malformed refresh token", 0, http.StatusUnauthorized)
		}

		// check the refresh token
		validToken, claims := u.tokenizer.Validate(ruser.RefreshToken, refreshSubject, sessionID+":"+sessionKey)
		if !validToken {
			return c.JSON(http.StatusUnauthorized, &resUserAuth{
				Valid: false,
			})
		}

		// create a new key for the session
		key, err := uid.NewU(0, 16)
		if err != nil {
			err.AddTrace(moduleIDAuth)
			return err
		}
		sessionKey = key.Base64()

		// generate a new refreshToken from the refreshToken claims
		refreshToken, err := u.tokenizer.GenerateFromClaims(claims, u.accessTime, refreshSubject, sessionID+":"+sessionKey)
		if err != nil {
			err.AddTrace(moduleIDAuth)
			return err
		}

		// set the session id and key into cache
		if err := ch.Set(sessionID, sessionKey, time.Duration(u.refreshTime*b1)).Err(); err != nil {
			return governor.NewError(moduleIDAuth, err.Error(), 0, http.StatusInternalServerError)
		}

		return c.JSON(http.StatusOK, &resUserAuth{
			Valid:        true,
			RefreshToken: refreshToken,
		})
	})

	if conf.IsDebug() {
		r.GET("/decode", func(c echo.Context) error {
			return c.JSON(http.StatusOK, resUserAuth{
				Valid:  true,
				Claims: c.Get("user").(*token.Claims),
			})
		}, u.gate.User())
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2014-2015 Bitmark Inc.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file

package services

import (
	"bufio"
	"crypto/tls"
	"github.com/bitmark-inc/bitmark-webgui/configuration"
	"github.com/bitmark-inc/bitmark-webgui/fault"
	"github.com/bitmark-inc/bitmark-webgui/utils"
	"github.com/bitmark-inc/bitmarkd/rpc"
	"github.com/bitmark-inc/logger"
	"net"
	netrpc "net/rpc"
	"os"
	"os/exec"
	"sync"
	"time"
)

type Bitmarkd struct {
	sync.RWMutex
	initialised bool
	log         *logger.L
	configFile  string
	process     *os.Process
	running     bool
	ModeStart   chan bool
}

func (bitmarkd *Bitmarkd) Initialise(configFile string) error {
	bitmarkd.Lock()
	defer bitmarkd.Unlock()

	if bitmarkd.initialised {
		return fault.ErrAlreadyInitialised
	}

	bitmarkd.configFile = configFile

	bitmarkd.log = logger.New("service-bitmarkd")
	if nil == bitmarkd.log {
		return fault.ErrInvalidLoggerChannel
	}

	bitmarkd.running = false
	bitmarkd.ModeStart = make(chan bool, 1)

	// all data initialised
	bitmarkd.initialised = true
	return nil
}

func (bitmarkd *Bitmarkd) Finalise() error {
	bitmarkd.Lock()
	defer bitmarkd.Unlock()

	if !bitmarkd.initialised {
		return fault.ErrNotInitialised
	}

	bitmarkd.initialised = false
	return nil
}

func (bitmarkd *Bitmarkd) IsRunning() bool {
	return bitmarkd.running
}

func (bitmarkd *Bitmarkd) Setup(bitmarkConfigFile string, webguiConfigFile string, webguiConfig *configuration.Configuration) error {
	if bitmarkd.running {
		return fault.ErrBitmarkdIsRunning
	}

	bitmarkd.configFile = bitmarkConfigFile

	webguiConfig.BitmarkConfigFile = bitmarkConfigFile
	return configuration.UpdateConfiguration(webguiConfigFile, webguiConfig)
}

func (bitmarkd *Bitmarkd) BitmarkdBackground(args interface{}, shutdown <-chan bool, finished chan<- bool) {
loop:
	for {
		select {

		case <-shutdown:
			break loop
		case start := <-bitmarkd.ModeStart:
			if start {
				bitmarkd.startBitmarkd()
			} else {
				bitmarkd.stopBitmarkd()
			}
		}

	}
	close(bitmarkd.ModeStart)
	close(finished)
}

func (bitmarkd *Bitmarkd) startBitmarkd() error {
	if bitmarkd.running {
		bitmarkd.log.Errorf("Start bitmarkd failed: %v", fault.ErrBitmarkdIsRunning)
		return fault.ErrBitmarkdIsRunning
	}

	// Check bitmarkConfigFile exists
	bitmarkd.log.Infof("bitmark config file: %s\n", bitmarkd.configFile)
	if !utils.EnsureFileExists(bitmarkd.configFile) {
		bitmarkd.log.Errorf("Start bitmarkd failed: %v", fault.ErrNotFoundConfigFile)
		return fault.ErrNotFoundConfigFile
	}

	// start bitmarkd as sub process
	cmd := exec.Command("bitmarkd", "--config-file="+bitmarkd.configFile)
	// start bitmarkd as sub process
	stderr, err := cmd.StderrPipe()
	if err != nil {
		bitmarkd.log.Errorf("Error: %v", err)
		return err
	}
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		bitmarkd.log.Errorf("Error: %v", err)
		return err
	}
	if err := cmd.Start(); nil != err {
		return err
	}

	bitmarkd.running = true
	bitmarkd.process = cmd.Process
	bitmarkd.log.Infof("process id: %d", cmd.Process.Pid)

	go func() {

		stdeReader := bufio.NewReader(stderr)
		stdoReader := bufio.NewReader(stdout)
		stderrDone := make(chan bool, 1)
		stdoutDone := make(chan bool, 1)

		go func() {
			defer close(stderrDone)
			for {
				stde, err := stdeReader.ReadString('\n')
				bitmarkd.log.Errorf("bitmarkd stderr: %q", stde)
				if nil != err {
					bitmarkd.log.Errorf("Error: %v", err)
					return
				}
			}
		}()

		go func() {
			defer close(stdoutDone)
			for {
				stdo, err := stdoReader.ReadString('\n')
				bitmarkd.log.Infof("bitmarkd stdout: %q", stdo)
				if nil != err {
					bitmarkd.log.Errorf("Error: %v", err)
					return
				}
			}
		}()

		<-stderrDone
		<-stdoutDone
		if err := cmd.Wait(); nil != err {
			bitmarkd.log.Errorf("Start bitmarkd failed: %v", err)
			bitmarkd.running = false
			bitmarkd.process = nil
		}
	}()

	// wait for 1 second if cmd has no error then return nil
	time.Sleep(time.Second * 1)
	return nil

}

func (bitmarkd *Bitmarkd) stopBitmarkd() error {
	if !bitmarkd.running {
		bitmarkd.log.Errorf("Stop bitmarkd failed: %v", fault.ErrBitmarkdIsNotRunning)
		return fault.ErrBitmarkdIsNotRunning
	}

	if err := bitmarkd.process.Signal(os.Interrupt); nil != err {
		bitmarkd.log.Errorf("Send interrupt to bitmarkd failed: %v", err)
		if err := bitmarkd.process.Signal(os.Kill); nil != err {
			bitmarkd.log.Errorf("Send kill to bitmarkd failed: %v", err)
			return err
		}
	}

	bitmarkd.log.Infof("Stop bitmarkd. PID: %d", bitmarkd.process.Pid)
	bitmarkd.running = false
	bitmarkd.process = nil
	return nil
}

func (bitmarkd *Bitmarkd) GetInfo(client *netrpc.Client) (*rpc.InfoReply, error) {

	var reply rpc.InfoReply
	if err := client.Call("Node.Info", rpc.InfoArguments{}, &reply); err != nil {
		bitmarkd.log.Errorf("Node.Info error: %v\n", err)
		return nil, fault.ErrNodeInfoRequestFail
	}

	return &reply, nil
}

// connect to bitmarkd RPC
func (bitmarkd *Bitmarkd) Connect(connect string) (net.Conn, error) {

	tlsConfig := &tls.Config{
		InsecureSkipVerify: true,
	}

	conn, err := tls.Dial("tcp", connect, tlsConfig)
	if nil != err {
		return nil, err
	}

	return conn, nil
}
<commit_msg>kill bitmark service directly<commit_after>// Copyright (c) 2014-2015 Bitmark Inc.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file

package services

import (
	"bufio"
	"crypto/tls"
	"github.com/bitmark-inc/bitmark-webgui/configuration"
	"github.com/bitmark-inc/bitmark-webgui/fault"
	"github.com/bitmark-inc/bitmark-webgui/utils"
	"github.com/bitmark-inc/bitmarkd/rpc"
	"github.com/bitmark-inc/logger"
	"net"
	netrpc "net/rpc"
	"os"
	"os/exec"
	"sync"
	"time"
)

type Bitmarkd struct {
	sync.RWMutex
	initialised bool
	log         *logger.L
	configFile  string
	process     *os.Process
	running     bool
	ModeStart   chan bool
}

func (bitmarkd *Bitmarkd) Initialise(configFile string) error {
	bitmarkd.Lock()
	defer bitmarkd.Unlock()

	if bitmarkd.initialised {
		return fault.ErrAlreadyInitialised
	}

	bitmarkd.configFile = configFile

	bitmarkd.log = logger.New("service-bitmarkd")
	if nil == bitmarkd.log {
		return fault.ErrInvalidLoggerChannel
	}

	bitmarkd.running = false
	bitmarkd.ModeStart = make(chan bool, 1)

	// all data initialised
	bitmarkd.initialised = true
	return nil
}

func (bitmarkd *Bitmarkd) Finalise() error {
	bitmarkd.Lock()
	defer bitmarkd.Unlock()

	if !bitmarkd.initialised {
		return fault.ErrNotInitialised
	}

	bitmarkd.initialised = false
	return nil
}

func (bitmarkd *Bitmarkd) IsRunning() bool {
	return bitmarkd.running
}

func (bitmarkd *Bitmarkd) Setup(bitmarkConfigFile string, webguiConfigFile string, webguiConfig *configuration.Configuration) error {
	if bitmarkd.running {
		return fault.ErrBitmarkdIsRunning
	}

	bitmarkd.configFile = bitmarkConfigFile

	webguiConfig.BitmarkConfigFile = bitmarkConfigFile
	return configuration.UpdateConfiguration(webguiConfigFile, webguiConfig)
}

func (bitmarkd *Bitmarkd) BitmarkdBackground(args interface{}, shutdown <-chan bool, finished chan<- bool) {
loop:
	for {
		select {

		case <-shutdown:
			break loop
		case start := <-bitmarkd.ModeStart:
			if start {
				bitmarkd.startBitmarkd()
			} else {
				bitmarkd.stopBitmarkd()
			}
		}

	}
	close(bitmarkd.ModeStart)
	close(finished)
}

func (bitmarkd *Bitmarkd) startBitmarkd() error {
	if bitmarkd.running {
		bitmarkd.log.Errorf("Start bitmarkd failed: %v", fault.ErrBitmarkdIsRunning)
		return fault.ErrBitmarkdIsRunning
	}

	// Check bitmarkConfigFile exists
	bitmarkd.log.Infof("bitmark config file: %s\n", bitmarkd.configFile)
	if !utils.EnsureFileExists(bitmarkd.configFile) {
		bitmarkd.log.Errorf("Start bitmarkd failed: %v", fault.ErrNotFoundConfigFile)
		return fault.ErrNotFoundConfigFile
	}

	// start bitmarkd as sub process
	cmd := exec.Command("bitmarkd", "--config-file="+bitmarkd.configFile)
	// start bitmarkd as sub process
	stderr, err := cmd.StderrPipe()
	if err != nil {
		bitmarkd.log.Errorf("Error: %v", err)
		return err
	}
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		bitmarkd.log.Errorf("Error: %v", err)
		return err
	}
	if err := cmd.Start(); nil != err {
		return err
	}

	bitmarkd.running = true
	bitmarkd.process = cmd.Process
	bitmarkd.log.Infof("process id: %d", cmd.Process.Pid)

	go func() {

		stdeReader := bufio.NewReader(stderr)
		stdoReader := bufio.NewReader(stdout)
		stderrDone := make(chan bool, 1)
		stdoutDone := make(chan bool, 1)

		go func() {
			defer close(stderrDone)
			for {
				stde, err := stdeReader.ReadString('\n')
				bitmarkd.log.Errorf("bitmarkd stderr: %q", stde)
				if nil != err {
					bitmarkd.log.Errorf("Error: %v", err)
					return
				}
			}
		}()

		go func() {
			defer close(stdoutDone)
			for {
				stdo, err := stdoReader.ReadString('\n')
				bitmarkd.log.Infof("bitmarkd stdout: %q", stdo)
				if nil != err {
					bitmarkd.log.Errorf("Error: %v", err)
					return
				}
			}
		}()

		<-stderrDone
		<-stdoutDone
		if err := cmd.Wait(); nil != err {
			bitmarkd.log.Errorf("Start bitmarkd failed: %v", err)
			bitmarkd.running = false
			bitmarkd.process = nil
		}
	}()

	// wait for 1 second if cmd has no error then return nil
	time.Sleep(time.Second * 1)
	return nil

}

func (bitmarkd *Bitmarkd) stopBitmarkd() error {
	if !bitmarkd.running {
		bitmarkd.log.Errorf("Stop bitmarkd failed: %v", fault.ErrBitmarkdIsNotRunning)
		return fault.ErrBitmarkdIsNotRunning
	}

	if err := bitmarkd.process.Kill(); nil != err {
		bitmarkd.log.Errorf("Send interrupt to bitmarkd failed: %v", err)
		return err
	}

	bitmarkd.log.Infof("Stop bitmarkd. PID: %d", bitmarkd.process.Pid)
	bitmarkd.running = false
	bitmarkd.process = nil
	return nil
}

func (bitmarkd *Bitmarkd) GetInfo(client *netrpc.Client) (*rpc.InfoReply, error) {

	var reply rpc.InfoReply
	if err := client.Call("Node.Info", rpc.InfoArguments{}, &reply); err != nil {
		bitmarkd.log.Errorf("Node.Info error: %v\n", err)
		return nil, fault.ErrNodeInfoRequestFail
	}

	return &reply, nil
}

// connect to bitmarkd RPC
func (bitmarkd *Bitmarkd) Connect(connect string) (net.Conn, error) {

	tlsConfig := &tls.Config{
		InsecureSkipVerify: true,
	}

	conn, err := tls.Dial("tcp", connect, tlsConfig)
	if nil != err {
		return nil, err
	}

	return conn, nil
}
<|endoftext|>


<commit_before>package google

import (
	"fmt"
	"testing"

	"github.com/hashicorp/terraform/helper/acctest"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

// Stackdriver tests cannot be run in parallel otherwise they will error out with:
// Error 503: Too many concurrent edits to the project configuration. Please try again.

func TestAccMonitoringAlertPolicy_basic(t *testing.T) {

	alertName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
	conditionName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
	filter := `metric.type=\"compute.googleapis.com/instance/disk/write_bytes_count\" AND resource.type=\"gce_instance\"`

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAlertPolicyDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccMonitoringAlertPolicy_basic(alertName, conditionName, "ALIGN_RATE", filter),
			},
			{
				ResourceName:      "google_monitoring_alert_policy.basic",
				ImportState:       true,
				ImportStateVerify: true,
			},
		},
	})
}

func TestAccMonitoringAlertPolicy_update(t *testing.T) {

	alertName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
	conditionName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
	filter1 := `metric.type=\"compute.googleapis.com/instance/disk/write_bytes_count\" AND resource.type=\"gce_instance\"`
	aligner1 := "ALIGN_RATE"
	filter2 := `metric.type=\"compute.googleapis.com/instance/cpu/utilization\" AND resource.type=\"gce_instance\"`
	aligner2 := "ALIGN_MAX"

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAlertPolicyDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccMonitoringAlertPolicy_basic(alertName, conditionName, aligner1, filter1),
			},
			{
				ResourceName:      "google_monitoring_alert_policy.basic",
				ImportState:       true,
				ImportStateVerify: true,
			},
			{
				Config: testAccMonitoringAlertPolicy_basic(alertName, conditionName, aligner2, filter2),
			},
			{
				ResourceName:      "google_monitoring_alert_policy.basic",
				ImportState:       true,
				ImportStateVerify: true,
			},
		},
	})
}

func TestAccMonitoringAlertPolicy_full(t *testing.T) {

	alertName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
	conditionName1 := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
	conditionName2 := fmt.Sprintf("tf-test-%s", acctest.RandString(10))

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAlertPolicyDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccMonitoringAlertPolicy_full(alertName, conditionName1, conditionName2),
			},
			{
				ResourceName:      "google_monitoring_alert_policy.full",
				ImportState:       true,
				ImportStateVerify: true,
			},
		},
	})
}

func testAccCheckAlertPolicyDestroy(s *terraform.State) error {
	config := testAccProvider.Meta().(*Config)

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "google_monitoring_alert_policy" {
			continue
		}

		name := rs.Primary.Attributes["name"]

		url := fmt.Sprintf("https://monitoring.googleapis.com/v3/%s", name)
		_, err := sendRequest(config, "GET", url, nil)

		if err == nil {
			return fmt.Errorf("Error, alert policy %s still exists", name)
		}
	}

	return nil
}

func testAccMonitoringAlertPolicy_basic(alertName, conditionName, aligner, filter string) string {
	return fmt.Sprintf(`
resource "google_monitoring_alert_policy" "basic" {
  display_name = "%s"
  enabled      = true
  combiner     = "OR"

  conditions {
    display_name = "%s"

    condition_threshold {
      aggregations {
        alignment_period   = "60s"
        per_series_aligner = "%s"
      }

      duration       = "60s"
      comparison     = "COMPARISON_GT"
      filter         = "%s"
      thresholdValue = "0.5"
    }
  }
}
`, alertName, conditionName, aligner, filter)
}

func testAccMonitoringAlertPolicy_full(alertName, conditionName1, conditionName2 string) string {
	return fmt.Sprintf(`
resource "google_monitoring_alert_policy" "full" {
  display_name = "%s"
  combiner     = "OR"
  enabled      = true

  conditions {
    display_name = "%s"

    condition_threshold {
      threshold_value = 50
      filter          = "metric.type=\"compute.googleapis.com/instance/disk/write_bytes_count\" AND resource.type=\"gce_instance\""
      duration        = "60s"
      comparison      = "COMPARISON_GT"

      aggregations {
        alignment_period     = "60s"
        per_series_aligner   = "ALIGN_RATE"
        cross_series_reducer = "REDUCE_MEAN"

        group_by_fields = [
          "metric.label.device_name",
          "project",
          "resource.label.instance_id",
          "resource.label.zone",
        ]
      }

      trigger {
        percent = 10
      }
    }
  }

  conditions {
    display_name = "%s"

    condition_absent {
      duration = "3600s"
      filter   = "metric.type=\"compute.googleapis.com/instance/cpu/utilization\" AND resource.type=\"gce_instance\""

      aggregations {
        alignment_period     = "60s"
        cross_series_reducer = "REDUCE_MEAN"
        per_series_aligner   = "ALIGN_MEAN"

        group_by_fields = [
          "project",
          "resource.label.instance_id",
          "resource.label.zone",
        ]
      }

      trigger {
        count = 1
      }
    }
  }

  documentation {
    content   = "test content"
    mime_type = "text/markdown"
  }
}
`, alertName, conditionName1, conditionName2)
}
<commit_msg>Fix bad monitoring test data (#292)<commit_after>package google

import (
	"fmt"
	"testing"

	"github.com/hashicorp/terraform/helper/acctest"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

// Stackdriver tests cannot be run in parallel otherwise they will error out with:
// Error 503: Too many concurrent edits to the project configuration. Please try again.

func TestAccMonitoringAlertPolicy_basic(t *testing.T) {

	alertName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
	conditionName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
	filter := `metric.type=\"compute.googleapis.com/instance/disk/write_bytes_count\" AND resource.type=\"gce_instance\"`

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAlertPolicyDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccMonitoringAlertPolicy_basic(alertName, conditionName, "ALIGN_RATE", filter),
			},
			{
				ResourceName:      "google_monitoring_alert_policy.basic",
				ImportState:       true,
				ImportStateVerify: true,
			},
		},
	})
}

func TestAccMonitoringAlertPolicy_update(t *testing.T) {

	alertName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
	conditionName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
	filter1 := `metric.type=\"compute.googleapis.com/instance/disk/write_bytes_count\" AND resource.type=\"gce_instance\"`
	aligner1 := "ALIGN_RATE"
	filter2 := `metric.type=\"compute.googleapis.com/instance/cpu/utilization\" AND resource.type=\"gce_instance\"`
	aligner2 := "ALIGN_MAX"

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAlertPolicyDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccMonitoringAlertPolicy_basic(alertName, conditionName, aligner1, filter1),
			},
			{
				ResourceName:      "google_monitoring_alert_policy.basic",
				ImportState:       true,
				ImportStateVerify: true,
			},
			{
				Config: testAccMonitoringAlertPolicy_basic(alertName, conditionName, aligner2, filter2),
			},
			{
				ResourceName:      "google_monitoring_alert_policy.basic",
				ImportState:       true,
				ImportStateVerify: true,
			},
		},
	})
}

func TestAccMonitoringAlertPolicy_full(t *testing.T) {

	alertName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
	conditionName1 := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
	conditionName2 := fmt.Sprintf("tf-test-%s", acctest.RandString(10))

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAlertPolicyDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccMonitoringAlertPolicy_full(alertName, conditionName1, conditionName2),
			},
			{
				ResourceName:      "google_monitoring_alert_policy.full",
				ImportState:       true,
				ImportStateVerify: true,
			},
		},
	})
}

func testAccCheckAlertPolicyDestroy(s *terraform.State) error {
	config := testAccProvider.Meta().(*Config)

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "google_monitoring_alert_policy" {
			continue
		}

		name := rs.Primary.Attributes["name"]

		url := fmt.Sprintf("https://monitoring.googleapis.com/v3/%s", name)
		_, err := sendRequest(config, "GET", url, nil)

		if err == nil {
			return fmt.Errorf("Error, alert policy %s still exists", name)
		}
	}

	return nil
}

func testAccMonitoringAlertPolicy_basic(alertName, conditionName, aligner, filter string) string {
	return fmt.Sprintf(`
resource "google_monitoring_alert_policy" "basic" {
  display_name = "%s"
  enabled      = true
  combiner     = "OR"

  conditions {
    display_name = "%s"

    condition_threshold {
      aggregations {
        alignment_period   = "60s"
        per_series_aligner = "%s"
      }

      duration       = "60s"
      comparison     = "COMPARISON_GT"
      filter         = "%s"
      threshold_value = "0.5"
    }
  }
}
`, alertName, conditionName, aligner, filter)
}

func testAccMonitoringAlertPolicy_full(alertName, conditionName1, conditionName2 string) string {
	return fmt.Sprintf(`
resource "google_monitoring_alert_policy" "full" {
  display_name = "%s"
  combiner     = "OR"
  enabled      = true

  conditions {
    display_name = "%s"

    condition_threshold {
      threshold_value = 50
      filter          = "metric.type=\"compute.googleapis.com/instance/disk/write_bytes_count\" AND resource.type=\"gce_instance\""
      duration        = "60s"
      comparison      = "COMPARISON_GT"

      aggregations {
        alignment_period     = "60s"
        per_series_aligner   = "ALIGN_RATE"
        cross_series_reducer = "REDUCE_MEAN"

        group_by_fields = [
          "metric.label.device_name",
          "project",
          "resource.label.instance_id",
          "resource.label.zone",
        ]
      }

      trigger {
        percent = 10
      }
    }
  }

  conditions {
    display_name = "%s"

    condition_absent {
      duration = "3600s"
      filter   = "metric.type=\"compute.googleapis.com/instance/cpu/utilization\" AND resource.type=\"gce_instance\""

      aggregations {
        alignment_period     = "60s"
        cross_series_reducer = "REDUCE_MEAN"
        per_series_aligner   = "ALIGN_MEAN"

        group_by_fields = [
          "project",
          "resource.label.instance_id",
          "resource.label.zone",
        ]
      }

      trigger {
        count = 1
      }
    }
  }

  documentation {
    content   = "test content"
    mime_type = "text/markdown"
  }
}
`, alertName, conditionName1, conditionName2)
}
<|endoftext|>