<commit_before>package kubernetes

import (
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/terraform"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	pkgApi "k8s.io/apimachinery/pkg/types"
	kubernetes "k8s.io/client-go/kubernetes"
	"k8s.io/client-go/pkg/apis/extensions/v1beta1"
)

func resourceKubernetesDeployment() *schema.Resource {
	return &schema.Resource{
		Create: resourceKubernetesDeploymentCreate,
		Read:   resourceKubernetesDeploymentRead,
		Exists: resourceKubernetesDeploymentExists,
		Update: resourceKubernetesDeploymentUpdate,
		Delete: resourceKubernetesDeploymentDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},
		SchemaVersion: 1,
		MigrateState:  resourceKubernetesDeploymentStateUpgrader,

		Timeouts: &schema.ResourceTimeout{
			Create: schema.DefaultTimeout(10 * time.Minute),
			Update: schema.DefaultTimeout(10 * time.Minute),
			Delete: schema.DefaultTimeout(10 * time.Minute),
		},

		Schema: map[string]*schema.Schema{
			"metadata": namespacedMetadataSchema("deployment", true),
			"name": {
				Type:     schema.TypeString,
				Optional: true,
				Removed:  "To better match the Kubernetes API, the name attribute should be configured under the metadata block. Please update your Terraform configuration.",
			},
			"spec": {
				Type:        schema.TypeList,
				Description: "Spec defines the specification of the desired behavior of the deployment. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status",
				Required:    true,
				MaxItems:    1,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"min_ready_seconds": {
							Type:        schema.TypeInt,
							Description: "Minimum number of seconds for which a newly created pod should be ready without any of its container crashing, for it to be considered available. Defaults to 0 (pod will be considered available as soon as it is ready)",
							Optional:    true,
							Default:     0,
						},
						"replicas": {
							Type:        schema.TypeInt,
							Description: "The number of desired replicas. Defaults to 1. More info: http://kubernetes.io/docs/user-guide/replication-controller#what-is-a-replication-controller",
							Optional:    true,
							Default:     1,
						},
						"selector": {
							Type:        schema.TypeMap,
							Description: "A label query over pods that should match the Replicas count. If Selector is empty, it is defaulted to the labels present on the Pod template. Label keys and values that must match in order to be controlled by this deployment, if empty defaulted to labels on Pod template. More info: http://kubernetes.io/docs/user-guide/labels#label-selectors",
							Optional:    true,
							Computed:    true,
						},
						"strategy": {
							Type:        schema.TypeList,
							Optional:    true,
							Computed:    true,
							Description: "Update strategy. One of RollingUpdate, Destroy. Defaults to RollingDate",
							MaxItems:    1,
							Elem: &schema.Resource{
								Schema: map[string]*schema.Schema{
									"type": {
										Type:        schema.TypeString,
										Optional:    true,
										Computed:    true,
										Description: "Update strategy",
									},
									"rolling_update": {
										Type:        schema.TypeList,
										Description: "rolling update",
										Optional:    true,
										Computed:    true,
										MaxItems:    1,
										Elem: &schema.Resource{
											Schema: map[string]*schema.Schema{
												"max_surge": {
													Type:        schema.TypeString,
													Description: "max surge",
													Optional:    true,
													Default:     1,
												},
												"max_unavailable": {
													Type:        schema.TypeString,
													Description: "max unavailable",
													Optional:    true,
													Default:     1,
												},
											},
										},
									},
								},
							},
						},
						"template": {
							Type:        schema.TypeList,
							Description: "Template describes the pods that will be created.",
							Required:    true,
							MaxItems:    1,
							Elem: &schema.Resource{
								Schema: map[string]*schema.Schema{
									"metadata": metadataSchema("deploymentSpec", true),
									"spec": &schema.Schema{
										Type:        schema.TypeList,
										Description: "Template describes the pods that will be created.",
										Required:    true,
										MaxItems:    1,
										Elem: &schema.Resource{
											Schema: podSpecFields(true),
										},
									},
									"active_deadline_seconds":          relocatedAttribute("active_deadline_seconds"),
									"container":                        relocatedAttribute("container"),
									"dns_policy":                       relocatedAttribute("dns_policy"),
									"host_ipc":                         relocatedAttribute("host_ipc"),
									"host_network":                     relocatedAttribute("host_network"),
									"host_pid":                         relocatedAttribute("host_pid"),
									"hostname":                         relocatedAttribute("hostname"),
									"init_container":                   relocatedAttribute("init_container"),
									"node_name":                        relocatedAttribute("node_name"),
									"node_selector":                    relocatedAttribute("node_selector"),
									"restart_policy":                   relocatedAttribute("restart_policy"),
									"security_context":                 relocatedAttribute("security_context"),
									"service_account_name":             relocatedAttribute("service_account_name"),
									"automount_service_account_token":  relocatedAttribute("automount_service_account_token"),
									"subdomain":                        relocatedAttribute("subdomain"),
									"termination_grace_period_seconds": relocatedAttribute("termination_grace_period_seconds"),
									"volume": relocatedAttribute("volume"),
								},
							},
						},
					},
				},
			},
		},
	}
}

func relocatedAttribute(name string) *schema.Schema {
	s := &schema.Schema{
		Type:     schema.TypeString,
		Optional: true,
		Removed:  fmt.Sprintf("%s has been relocated to [resource]/spec/template/spec/%s. Please update your Terraform config.", name, name),
	}
	return s
}

func resourceKubernetesDeploymentCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*kubernetes.Clientset)

	metadata := expandMetadata(d.Get("metadata").([]interface{}))
	spec, err := expandDeploymentSpec(d.Get("spec").([]interface{}))
	if err != nil {
		return err
	}
	if metadata.Namespace == "" {
		metadata.Namespace = "default"
	}

	deployment := v1beta1.Deployment{
		ObjectMeta: metadata,
		Spec:       spec,
	}

	log.Printf("[INFO] Creating new deployment: %#v", deployment)
	out, err := conn.ExtensionsV1beta1().Deployments(metadata.Namespace).Create(&deployment)
	if err != nil {
		return fmt.Errorf("Failed to create deployment: %s", err)
	}

	d.SetId(buildId(out.ObjectMeta))

	log.Printf("[DEBUG] Waiting for deployment %s to schedule %d replicas",
		d.Id(), *out.Spec.Replicas)
	// 10 mins should be sufficient for scheduling ~10k replicas
	err = resource.Retry(d.Timeout(schema.TimeoutCreate),
		waitForDeploymentReplicasFunc(conn, out.GetNamespace(), out.GetName()))
	if err != nil {
		return err
	}
	// We could wait for all pods to actually reach Ready state
	// but that means checking each pod status separately (which can be expensive at scale)
	// as there's no aggregate data available from the API

	log.Printf("[INFO] Submitted new deployment: %#v", out)

	return resourceKubernetesDeploymentRead(d, meta)
}

func resourceKubernetesDeploymentRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*kubernetes.Clientset)

	namespace, name, err := idParts(d.Id())
	log.Printf("[INFO] Reading deployment %s", name)
	deployment, err := conn.ExtensionsV1beta1().Deployments(namespace).Get(name, metav1.GetOptions{})
	if err != nil {
		log.Printf("[DEBUG] Received error: %#v", err)
		return err
	}
	log.Printf("[INFO] Received deployment: %#v", deployment)

	err = d.Set("metadata", flattenMetadata(deployment.ObjectMeta, d))
	if err != nil {
		return err
	}

	spec, err := flattenDeploymentSpec(deployment.Spec, d)
	if err != nil {
		return err
	}

	err = d.Set("spec", spec)
	if err != nil {
		return err
	}

	return nil
}

func resourceKubernetesDeploymentUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*kubernetes.Clientset)

	namespace, name, err := idParts(d.Id())

	ops := patchMetadata("metadata.0.", "/metadata/", d)

	if d.HasChange("spec") {
		spec, err := expandDeploymentSpec(d.Get("spec").([]interface{}))
		if err != nil {
			return err
		}

		ops = append(ops, &ReplaceOperation{
			Path:  "/spec",
			Value: spec,
		})
	}
	data, err := ops.MarshalJSON()
	if err != nil {
		return fmt.Errorf("Failed to marshal update operations: %s", err)
	}
	log.Printf("[INFO] Updating deployment %q: %v", name, string(data))
	out, err := conn.ExtensionsV1beta1().Deployments(namespace).Patch(name, pkgApi.JSONPatchType, data)
	if err != nil {
		return fmt.Errorf("Failed to update deployment: %s", err)
	}
	log.Printf("[INFO] Submitted updated deployment: %#v", out)

	err = resource.Retry(d.Timeout(schema.TimeoutUpdate),
		waitForDeploymentReplicasFunc(conn, namespace, name))
	if err != nil {
		return err
	}

	return resourceKubernetesDeploymentRead(d, meta)
}

func resourceKubernetesDeploymentDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*kubernetes.Clientset)

	namespace, name, err := idParts(d.Id())
	log.Printf("[INFO] Deleting deployment: %#v", name)

	// Drain all replicas before deleting
	var ops PatchOperations
	ops = append(ops, &ReplaceOperation{
		Path:  "/spec/replicas",
		Value: 0,
	})
	data, err := ops.MarshalJSON()
	if err != nil {
		return err
	}
	_, err = conn.ExtensionsV1beta1().Deployments(namespace).Patch(name, pkgApi.JSONPatchType, data)
	if err != nil {
		return err
	}

	// Wait until all replicas are gone
	err = resource.Retry(d.Timeout(schema.TimeoutDelete),
		waitForDeploymentReplicasFunc(conn, namespace, name))
	if err != nil {
		return err
	}

	err = conn.ExtensionsV1beta1().Deployments(namespace).Delete(name, &metav1.DeleteOptions{})
	if err != nil {
		return err
	}

	log.Printf("[INFO] Deployment %s deleted", name)

	d.SetId("")
	return nil
}

func resourceKubernetesDeploymentExists(d *schema.ResourceData, meta interface{}) (bool, error) {
	conn := meta.(*kubernetes.Clientset)

	namespace, name, err := idParts(d.Id())
	log.Printf("[INFO] Checking deployment %s", name)
	_, err = conn.ExtensionsV1beta1().Deployments(namespace).Get(name, metav1.GetOptions{})
	if err != nil {
		if statusErr, ok := err.(*errors.StatusError); ok && statusErr.ErrStatus.Code == 404 {
			return false, nil
		}
		log.Printf("[DEBUG] Received error: %#v", err)
	}
	return true, err
}

func waitForDeploymentReplicasFunc(conn *kubernetes.Clientset, ns, name string) resource.RetryFunc {
	return func() *resource.RetryError {
		deployment, err := conn.ExtensionsV1beta1().Deployments(ns).Get(name, metav1.GetOptions{})
		if err != nil {
			return resource.NonRetryableError(err)
		}

		desiredReplicas := *deployment.Spec.Replicas
		log.Printf("[DEBUG] Current number of labelled replicas of %q: %d (of %d)\n",
			deployment.GetName(), deployment.Status.Replicas, desiredReplicas)

		if deployment.Status.Replicas == desiredReplicas {
			return nil
		}

		return resource.RetryableError(fmt.Errorf("Waiting for %d replicas of %q to be scheduled (%d)",
			desiredReplicas, deployment.GetName(), deployment.Status.Replicas))
	}
}

func resourceKubernetesDeploymentStateUpgrader(
	v int, is *terraform.InstanceState, meta interface{}) (*terraform.InstanceState, error) {
	if is.Empty() {
		log.Println("[DEBUG] Empty InstanceState; nothing to migrate.")
		return is, nil
	}

	var err error

	switch v {
	case 0:
		log.Println("[INFO] Found Kubernetes Deployment State v0; migrating to v1")
		is, err = migrateStateV0toV1(is)
		if err != nil {
			return is, err
		}

	default:
		return is, fmt.Errorf("Unexpected schema version: %d", v)
	}

	return is, err
}

// This deployment resource originally had the podSpec directly below spec.template level
// This migration moves the state to spec.template.spec match the Kubernetes documented structure
func migrateStateV0toV1(is *terraform.InstanceState) (*terraform.InstanceState, error) {
	log.Printf("[DEBUG] Attributes before migration: %#v", is.Attributes)

	newTemplate := make(map[string]string)

	for k, v := range is.Attributes {
		log.Println("[DEBUG] - checking attribute for state upgrade: ", k, v)
		if strings.HasPrefix(k, "name") {
			// don't clobber an existing metadata.0.name value
			if _, ok := is.Attributes["metadata.0.name"]; ok {
				continue
			}

			newK := "metadata.0.name"

			newTemplate[newK] = v
			log.Printf("[DEBUG] moved attribute %s -> %s ", k, newK)
			delete(is.Attributes, k)

		} else if !strings.HasPrefix(k, "spec.0.template") {
			continue

		} else if strings.HasPrefix(k, "spec.0.template.0.spec") || strings.HasPrefix(k, "spec.0.template.0.metadata") {
			continue

		} else {
			newK := strings.Replace(k, "spec.0.template.0", "spec.0.template.0.spec.0", 1)

			newTemplate[newK] = v
			log.Printf("[DEBUG] moved attribute %s -> %s ", k, newK)
			delete(is.Attributes, k)
		}
	}

	for k, v := range newTemplate {
		is.Attributes[k] = v
	}

	log.Printf("[DEBUG] Attributes after migration: %#v", is.Attributes)
	return is, nil
}
<commit_msg>Set DeletionPolicyForeground on deployment delete<commit_after>package kubernetes

import (
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/terraform"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	pkgApi "k8s.io/apimachinery/pkg/types"
	kubernetes "k8s.io/client-go/kubernetes"
	"k8s.io/client-go/pkg/apis/extensions/v1beta1"
)

func resourceKubernetesDeployment() *schema.Resource {
	return &schema.Resource{
		Create: resourceKubernetesDeploymentCreate,
		Read:   resourceKubernetesDeploymentRead,
		Exists: resourceKubernetesDeploymentExists,
		Update: resourceKubernetesDeploymentUpdate,
		Delete: resourceKubernetesDeploymentDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},
		SchemaVersion: 1,
		MigrateState:  resourceKubernetesDeploymentStateUpgrader,

		Timeouts: &schema.ResourceTimeout{
			Create: schema.DefaultTimeout(10 * time.Minute),
			Update: schema.DefaultTimeout(10 * time.Minute),
			Delete: schema.DefaultTimeout(10 * time.Minute),
		},

		Schema: map[string]*schema.Schema{
			"metadata": namespacedMetadataSchema("deployment", true),
			"name": {
				Type:     schema.TypeString,
				Optional: true,
				Removed:  "To better match the Kubernetes API, the name attribute should be configured under the metadata block. Please update your Terraform configuration.",
			},
			"spec": {
				Type:        schema.TypeList,
				Description: "Spec defines the specification of the desired behavior of the deployment. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status",
				Required:    true,
				MaxItems:    1,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"min_ready_seconds": {
							Type:        schema.TypeInt,
							Description: "Minimum number of seconds for which a newly created pod should be ready without any of its container crashing, for it to be considered available. Defaults to 0 (pod will be considered available as soon as it is ready)",
							Optional:    true,
							Default:     0,
						},
						"replicas": {
							Type:        schema.TypeInt,
							Description: "The number of desired replicas. Defaults to 1. More info: http://kubernetes.io/docs/user-guide/replication-controller#what-is-a-replication-controller",
							Optional:    true,
							Default:     1,
						},
						"selector": {
							Type:        schema.TypeMap,
							Description: "A label query over pods that should match the Replicas count. If Selector is empty, it is defaulted to the labels present on the Pod template. Label keys and values that must match in order to be controlled by this deployment, if empty defaulted to labels on Pod template. More info: http://kubernetes.io/docs/user-guide/labels#label-selectors",
							Optional:    true,
							Computed:    true,
						},
						"strategy": {
							Type:        schema.TypeList,
							Optional:    true,
							Computed:    true,
							Description: "Update strategy. One of RollingUpdate, Destroy. Defaults to RollingDate",
							MaxItems:    1,
							Elem: &schema.Resource{
								Schema: map[string]*schema.Schema{
									"type": {
										Type:        schema.TypeString,
										Optional:    true,
										Computed:    true,
										Description: "Update strategy",
									},
									"rolling_update": {
										Type:        schema.TypeList,
										Description: "rolling update",
										Optional:    true,
										Computed:    true,
										MaxItems:    1,
										Elem: &schema.Resource{
											Schema: map[string]*schema.Schema{
												"max_surge": {
													Type:        schema.TypeString,
													Description: "max surge",
													Optional:    true,
													Default:     1,
												},
												"max_unavailable": {
													Type:        schema.TypeString,
													Description: "max unavailable",
													Optional:    true,
													Default:     1,
												},
											},
										},
									},
								},
							},
						},
						"template": {
							Type:        schema.TypeList,
							Description: "Template describes the pods that will be created.",
							Required:    true,
							MaxItems:    1,
							Elem: &schema.Resource{
								Schema: map[string]*schema.Schema{
									"metadata": metadataSchema("deploymentSpec", true),
									"spec": &schema.Schema{
										Type:        schema.TypeList,
										Description: "Template describes the pods that will be created.",
										Required:    true,
										MaxItems:    1,
										Elem: &schema.Resource{
											Schema: podSpecFields(true),
										},
									},
									"active_deadline_seconds":          relocatedAttribute("active_deadline_seconds"),
									"container":                        relocatedAttribute("container"),
									"dns_policy":                       relocatedAttribute("dns_policy"),
									"host_ipc":                         relocatedAttribute("host_ipc"),
									"host_network":                     relocatedAttribute("host_network"),
									"host_pid":                         relocatedAttribute("host_pid"),
									"hostname":                         relocatedAttribute("hostname"),
									"init_container":                   relocatedAttribute("init_container"),
									"node_name":                        relocatedAttribute("node_name"),
									"node_selector":                    relocatedAttribute("node_selector"),
									"restart_policy":                   relocatedAttribute("restart_policy"),
									"security_context":                 relocatedAttribute("security_context"),
									"service_account_name":             relocatedAttribute("service_account_name"),
									"automount_service_account_token":  relocatedAttribute("automount_service_account_token"),
									"subdomain":                        relocatedAttribute("subdomain"),
									"termination_grace_period_seconds": relocatedAttribute("termination_grace_period_seconds"),
									"volume": relocatedAttribute("volume"),
								},
							},
						},
					},
				},
			},
		},
	}
}

func relocatedAttribute(name string) *schema.Schema {
	s := &schema.Schema{
		Type:     schema.TypeString,
		Optional: true,
		Removed:  fmt.Sprintf("%s has been relocated to [resource]/spec/template/spec/%s. Please update your Terraform config.", name, name),
	}
	return s
}

func resourceKubernetesDeploymentCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*kubernetes.Clientset)

	metadata := expandMetadata(d.Get("metadata").([]interface{}))
	spec, err := expandDeploymentSpec(d.Get("spec").([]interface{}))
	if err != nil {
		return err
	}
	if metadata.Namespace == "" {
		metadata.Namespace = "default"
	}

	deployment := v1beta1.Deployment{
		ObjectMeta: metadata,
		Spec:       spec,
	}

	log.Printf("[INFO] Creating new deployment: %#v", deployment)
	out, err := conn.ExtensionsV1beta1().Deployments(metadata.Namespace).Create(&deployment)
	if err != nil {
		return fmt.Errorf("Failed to create deployment: %s", err)
	}

	d.SetId(buildId(out.ObjectMeta))

	log.Printf("[DEBUG] Waiting for deployment %s to schedule %d replicas",
		d.Id(), *out.Spec.Replicas)
	// 10 mins should be sufficient for scheduling ~10k replicas
	err = resource.Retry(d.Timeout(schema.TimeoutCreate),
		waitForDeploymentReplicasFunc(conn, out.GetNamespace(), out.GetName()))
	if err != nil {
		return err
	}
	// We could wait for all pods to actually reach Ready state
	// but that means checking each pod status separately (which can be expensive at scale)
	// as there's no aggregate data available from the API

	log.Printf("[INFO] Submitted new deployment: %#v", out)

	return resourceKubernetesDeploymentRead(d, meta)
}

func resourceKubernetesDeploymentRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*kubernetes.Clientset)

	namespace, name, err := idParts(d.Id())
	log.Printf("[INFO] Reading deployment %s", name)
	deployment, err := conn.ExtensionsV1beta1().Deployments(namespace).Get(name, metav1.GetOptions{})
	if err != nil {
		log.Printf("[DEBUG] Received error: %#v", err)
		return err
	}
	log.Printf("[INFO] Received deployment: %#v", deployment)

	err = d.Set("metadata", flattenMetadata(deployment.ObjectMeta, d))
	if err != nil {
		return err
	}

	spec, err := flattenDeploymentSpec(deployment.Spec, d)
	if err != nil {
		return err
	}

	err = d.Set("spec", spec)
	if err != nil {
		return err
	}

	return nil
}

func resourceKubernetesDeploymentUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*kubernetes.Clientset)

	namespace, name, err := idParts(d.Id())

	ops := patchMetadata("metadata.0.", "/metadata/", d)

	if d.HasChange("spec") {
		spec, err := expandDeploymentSpec(d.Get("spec").([]interface{}))
		if err != nil {
			return err
		}

		ops = append(ops, &ReplaceOperation{
			Path:  "/spec",
			Value: spec,
		})
	}
	data, err := ops.MarshalJSON()
	if err != nil {
		return fmt.Errorf("Failed to marshal update operations: %s", err)
	}
	log.Printf("[INFO] Updating deployment %q: %v", name, string(data))
	out, err := conn.ExtensionsV1beta1().Deployments(namespace).Patch(name, pkgApi.JSONPatchType, data)
	if err != nil {
		return fmt.Errorf("Failed to update deployment: %s", err)
	}
	log.Printf("[INFO] Submitted updated deployment: %#v", out)

	err = resource.Retry(d.Timeout(schema.TimeoutUpdate),
		waitForDeploymentReplicasFunc(conn, namespace, name))
	if err != nil {
		return err
	}

	return resourceKubernetesDeploymentRead(d, meta)
}

func resourceKubernetesDeploymentDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*kubernetes.Clientset)

	namespace, name, err := idParts(d.Id())
	log.Printf("[INFO] Deleting deployment: %#v", name)

	// Drain all replicas before deleting
	var ops PatchOperations
	ops = append(ops, &ReplaceOperation{
		Path:  "/spec/replicas",
		Value: 0,
	})
	data, err := ops.MarshalJSON()
	if err != nil {
		return err
	}
	_, err = conn.ExtensionsV1beta1().Deployments(namespace).Patch(name, pkgApi.JSONPatchType, data)
	if err != nil {
		return err
	}

	// Wait until all replicas are gone
	err = resource.Retry(d.Timeout(schema.TimeoutDelete),
		waitForDeploymentReplicasFunc(conn, namespace, name))
	if err != nil {
		return err
	}

	policy := metav1.DeletePropagationForeground
	err = conn.ExtensionsV1beta1().Deployments(namespace).Delete(name, &metav1.DeleteOptions{
		PropagationPolicy: &policy,
	})
	if err != nil {
		return err
	}

	log.Printf("[INFO] Deployment %s deleted", name)

	d.SetId("")
	return nil
}

func resourceKubernetesDeploymentExists(d *schema.ResourceData, meta interface{}) (bool, error) {
	conn := meta.(*kubernetes.Clientset)

	namespace, name, err := idParts(d.Id())
	log.Printf("[INFO] Checking deployment %s", name)
	_, err = conn.ExtensionsV1beta1().Deployments(namespace).Get(name, metav1.GetOptions{})
	if err != nil {
		if statusErr, ok := err.(*errors.StatusError); ok && statusErr.ErrStatus.Code == 404 {
			return false, nil
		}
		log.Printf("[DEBUG] Received error: %#v", err)
	}
	return true, err
}

func waitForDeploymentReplicasFunc(conn *kubernetes.Clientset, ns, name string) resource.RetryFunc {
	return func() *resource.RetryError {
		deployment, err := conn.ExtensionsV1beta1().Deployments(ns).Get(name, metav1.GetOptions{})
		if err != nil {
			return resource.NonRetryableError(err)
		}

		desiredReplicas := *deployment.Spec.Replicas
		log.Printf("[DEBUG] Current number of labelled replicas of %q: %d (of %d)\n",
			deployment.GetName(), deployment.Status.Replicas, desiredReplicas)

		if deployment.Status.Replicas == desiredReplicas {
			return nil
		}

		return resource.RetryableError(fmt.Errorf("Waiting for %d replicas of %q to be scheduled (%d)",
			desiredReplicas, deployment.GetName(), deployment.Status.Replicas))
	}
}

func resourceKubernetesDeploymentStateUpgrader(
	v int, is *terraform.InstanceState, meta interface{}) (*terraform.InstanceState, error) {
	if is.Empty() {
		log.Println("[DEBUG] Empty InstanceState; nothing to migrate.")
		return is, nil
	}

	var err error

	switch v {
	case 0:
		log.Println("[INFO] Found Kubernetes Deployment State v0; migrating to v1")
		is, err = migrateStateV0toV1(is)
		if err != nil {
			return is, err
		}

	default:
		return is, fmt.Errorf("Unexpected schema version: %d", v)
	}

	return is, err
}

// This deployment resource originally had the podSpec directly below spec.template level
// This migration moves the state to spec.template.spec match the Kubernetes documented structure
func migrateStateV0toV1(is *terraform.InstanceState) (*terraform.InstanceState, error) {
	log.Printf("[DEBUG] Attributes before migration: %#v", is.Attributes)

	newTemplate := make(map[string]string)

	for k, v := range is.Attributes {
		log.Println("[DEBUG] - checking attribute for state upgrade: ", k, v)
		if strings.HasPrefix(k, "name") {
			// don't clobber an existing metadata.0.name value
			if _, ok := is.Attributes["metadata.0.name"]; ok {
				continue
			}

			newK := "metadata.0.name"

			newTemplate[newK] = v
			log.Printf("[DEBUG] moved attribute %s -> %s ", k, newK)
			delete(is.Attributes, k)

		} else if !strings.HasPrefix(k, "spec.0.template") {
			continue

		} else if strings.HasPrefix(k, "spec.0.template.0.spec") || strings.HasPrefix(k, "spec.0.template.0.metadata") {
			continue

		} else {
			newK := strings.Replace(k, "spec.0.template.0", "spec.0.template.0.spec.0", 1)

			newTemplate[newK] = v
			log.Printf("[DEBUG] moved attribute %s -> %s ", k, newK)
			delete(is.Attributes, k)
		}
	}

	for k, v := range newTemplate {
		is.Attributes[k] = v
	}

	log.Printf("[DEBUG] Attributes after migration: %#v", is.Attributes)
	return is, nil
}
<|endoftext|>


<commit_before>package handlers

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"

	"github.com/aws/aws-lambda-go/events"
	"github.com/grokify/chathooks/src/adapters"
	"github.com/grokify/chathooks/src/config"
	"github.com/grokify/chathooks/src/models"
	cc "github.com/grokify/commonchat"
	"github.com/grokify/gotilla/net/anyhttp"
	log "github.com/sirupsen/logrus"
	"github.com/valyala/fasthttp"
)

const (
	DisplayName = "base_handler"
)

type Handler struct {
	Config          config.Configuration
	AdapterSet      adapters.AdapterSet
	Key             string
	Normalize       Normalize
	MessageBodyType models.MessageBodyType
}

type HandlerRequest struct {
	Env         map[string]string // handler environment
	QueryParams url.Values        // query string params
	Body        []byte            // message, e.g. request body
}

func NewHandlerRequest() HandlerRequest {
	return HandlerRequest{
		Env:         map[string]string{},
		QueryParams: url.Values{},
		Body:        []byte("")}
}

type Normalize func(config.Configuration, HandlerRequest) (cc.Message, error)

// type Normalize func(config.Configuration, []byte) (cc.Message, error)

// HandleAwsLambda is the method to respond to a fasthttp request.
func (h Handler) HandleAwsLambda(ctx context.Context, awsReq events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
	hookData := models.HookDataFromAwsLambdaEvent(h.MessageBodyType, awsReq)
	errs := h.HandleCanonical(hookData)
	awsRes, err := models.BuildAwsAPIGatewayProxyResponse(hookData, errs...)
	return awsRes, err
}

/* DEPRECATE - REMOVE
// HandleEawsyLambda is the method to respond to a fasthttp request.
func (h Handler) HandleEawsyLambda(event *apigatewayproxyevt.Event, ctx *runtime.Context) (events.APIGatewayProxyResponse, error) {
	hookData := models.HookDataFromEawsyLambdaEvent(h.MessageBodyType, event)
	errs := h.HandleCanonical(hookData)
	awsRes, err := models.BuildAwsAPIGatewayProxyResponse(hookData, errs...)
	return awsRes, err
}*/

// HandleNetHTTP is the method to respond to a fasthttp request.
func (h Handler) HandleAnyHTTP(aRes anyhttp.Response, aReq anyhttp.Request) {
	hookData := models.HookDataFromAnyHTTPReq(h.MessageBodyType, aReq)
	errs := h.HandleCanonical(hookData)

	awsRes, err := models.BuildAwsAPIGatewayProxyResponse(hookData, errs...)

	if err != nil {
		aRes.SetStatusCode(http.StatusInternalServerError)
		log.WithFields(log.Fields{
			"event":   "outgoing.webhook.error",
			"handler": err.Error()}).Info("ERROR")
	} else {
		if bytes, err := json.Marshal(awsRes.Body); err != nil {
			aRes.SetStatusCode(http.StatusInternalServerError)
		} else {
			_, err := aRes.SetBodyBytes(bytes)
			if err != nil {
				log.WithFields(log.Fields{
					"event":   "outgoing.webhook.error",
					"handler": err.Error()}).Info("ERROR")
				aRes.SetStatusCode(http.StatusInternalServerError)
			} else {
				aRes.SetStatusCode(awsRes.StatusCode)
			}
		}
	}
}

// HandleNetHTTP is the method to respond to a fasthttp request.
func (h Handler) HandleNetHTTP(res http.ResponseWriter, req *http.Request) {
	hookData := models.HookDataFromNetHTTPReq(h.MessageBodyType, req)
	errs := h.HandleCanonical(hookData)

	awsRes, err := models.BuildAwsAPIGatewayProxyResponse(hookData, errs...)

	if err != nil {
		res.WriteHeader(http.StatusInternalServerError)
		log.WithFields(log.Fields{
			"event":   "outgoing.webhook.error",
			"handler": err.Error()}).Info("ERROR")
	} else {
		res.WriteHeader(awsRes.StatusCode)
		fmt.Fprint(res, awsRes.Body)
	}
}

// HandleFastHTTP is the method to respond to a fasthttp request.
func (h Handler) HandleFastHTTP(ctx *fasthttp.RequestCtx) {
	hookData := models.HookDataFromFastHTTPReqCtx(h.MessageBodyType, ctx)
	errs := h.HandleCanonical(hookData)

	awsRes, err := models.BuildAwsAPIGatewayProxyResponse(hookData, errs...)

	if err != nil {
		ctx.SetStatusCode(http.StatusInternalServerError)
		log.WithFields(log.Fields{
			"event":   "outgoing.webhook.error",
			"handler": err.Error()}).Info("ERROR")
	} else {
		ctx.SetStatusCode(awsRes.StatusCode)
		fmt.Fprint(ctx, awsRes.Body)
	}
}

// HandleCanonical is the method to handle a processed request.
func (h Handler) HandleCanonical(hookData models.HookData) []models.ErrorInfo {
	log.WithFields(log.Fields{
		"event":   "incoming.webhook",
		"handler": DisplayName}).Info("HANDLE_CANONICAL")
	log.WithFields(log.Fields{
		"event":   "incoming.webhook",
		"handler": DisplayName}).Info(string(hookData.InputBody))

	ccMsg, err := h.Normalize(h.Config,
		HandlerRequest{
			QueryParams: hookData.CustomQueryParams,
			Body:        hookData.InputBody})

	if err != nil {
		log.WithFields(log.Fields{
			"type":         "http.response",
			"status":       fasthttp.StatusNotAcceptable,
			"errorMessage": err.Error(),
		}).Info(fmt.Sprintf("%v request conversion failed.", DisplayName))
		return []models.ErrorInfo{{StatusCode: 500, Body: []byte(err.Error())}}
	}
	hookData.CanonicalMessage = ccMsg
	return h.AdapterSet.SendWebhooks(hookData)
}
<commit_msg>remove AWS Eawsy code<commit_after>package handlers

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"

	"github.com/aws/aws-lambda-go/events"
	"github.com/grokify/chathooks/src/adapters"
	"github.com/grokify/chathooks/src/config"
	"github.com/grokify/chathooks/src/models"
	cc "github.com/grokify/commonchat"
	"github.com/grokify/gotilla/net/anyhttp"
	log "github.com/sirupsen/logrus"
	"github.com/valyala/fasthttp"
)

const (
	DisplayName = "base_handler"
)

type Handler struct {
	Config          config.Configuration
	AdapterSet      adapters.AdapterSet
	Key             string
	Normalize       Normalize
	MessageBodyType models.MessageBodyType
}

type HandlerRequest struct {
	Env         map[string]string // handler environment
	QueryParams url.Values        // query string params
	Body        []byte            // message, e.g. request body
}

func NewHandlerRequest() HandlerRequest {
	return HandlerRequest{
		Env:         map[string]string{},
		QueryParams: url.Values{},
		Body:        []byte("")}
}

type Normalize func(config.Configuration, HandlerRequest) (cc.Message, error)

// HandleAwsLambda is the method to respond to a fasthttp request.
func (h Handler) HandleAwsLambda(ctx context.Context, awsReq events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
	hookData := models.HookDataFromAwsLambdaEvent(h.MessageBodyType, awsReq)
	errs := h.HandleCanonical(hookData)
	awsRes, err := models.BuildAwsAPIGatewayProxyResponse(hookData, errs...)
	return awsRes, err
}

// HandleNetHTTP is the method to respond to a fasthttp request.
func (h Handler) HandleAnyHTTP(aRes anyhttp.Response, aReq anyhttp.Request) {
	hookData := models.HookDataFromAnyHTTPReq(h.MessageBodyType, aReq)
	errs := h.HandleCanonical(hookData)

	awsRes, err := models.BuildAwsAPIGatewayProxyResponse(hookData, errs...)

	if err != nil {
		aRes.SetStatusCode(http.StatusInternalServerError)
		log.WithFields(log.Fields{
			"event":   "outgoing.webhook.error",
			"handler": err.Error()}).Info("ERROR")
	} else {
		if bytes, err := json.Marshal(awsRes.Body); err != nil {
			aRes.SetStatusCode(http.StatusInternalServerError)
		} else {
			_, err := aRes.SetBodyBytes(bytes)
			if err != nil {
				log.WithFields(log.Fields{
					"event":   "outgoing.webhook.error",
					"handler": err.Error()}).Info("ERROR")
				aRes.SetStatusCode(http.StatusInternalServerError)
			} else {
				aRes.SetStatusCode(awsRes.StatusCode)
			}
		}
	}
}

// HandleNetHTTP is the method to respond to a fasthttp request.
func (h Handler) HandleNetHTTP(res http.ResponseWriter, req *http.Request) {
	hookData := models.HookDataFromNetHTTPReq(h.MessageBodyType, req)
	errs := h.HandleCanonical(hookData)

	awsRes, err := models.BuildAwsAPIGatewayProxyResponse(hookData, errs...)

	if err != nil {
		res.WriteHeader(http.StatusInternalServerError)
		log.WithFields(log.Fields{
			"event":   "outgoing.webhook.error",
			"handler": err.Error()}).Info("ERROR")
	} else {
		res.WriteHeader(awsRes.StatusCode)
		fmt.Fprint(res, awsRes.Body)
	}
}

// HandleFastHTTP is the method to respond to a fasthttp request.
func (h Handler) HandleFastHTTP(ctx *fasthttp.RequestCtx) {
	hookData := models.HookDataFromFastHTTPReqCtx(h.MessageBodyType, ctx)
	errs := h.HandleCanonical(hookData)

	awsRes, err := models.BuildAwsAPIGatewayProxyResponse(hookData, errs...)

	if err != nil {
		ctx.SetStatusCode(http.StatusInternalServerError)
		log.WithFields(log.Fields{
			"event":   "outgoing.webhook.error",
			"handler": err.Error()}).Info("ERROR")
	} else {
		ctx.SetStatusCode(awsRes.StatusCode)
		fmt.Fprint(ctx, awsRes.Body)
	}
}

// HandleCanonical is the method to handle a processed request.
func (h Handler) HandleCanonical(hookData models.HookData) []models.ErrorInfo {
	log.WithFields(log.Fields{
		"event":   "incoming.webhook",
		"handler": DisplayName}).Info("HANDLE_CANONICAL")
	log.WithFields(log.Fields{
		"event":   "incoming.webhook",
		"handler": DisplayName}).Info(string(hookData.InputBody))

	ccMsg, err := h.Normalize(h.Config,
		HandlerRequest{
			QueryParams: hookData.CustomQueryParams,
			Body:        hookData.InputBody})

	if err != nil {
		log.WithFields(log.Fields{
			"type":         "http.response",
			"status":       fasthttp.StatusNotAcceptable,
			"errorMessage": err.Error(),
		}).Info(fmt.Sprintf("%v request conversion failed.", DisplayName))
		return []models.ErrorInfo{{StatusCode: 500, Body: []byte(err.Error())}}
	}
	hookData.CanonicalMessage = ccMsg
	return h.AdapterSet.SendWebhooks(hookData)
}
<|endoftext|>


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

package crc32

import (
	"hash"
	"math/rand"
	"testing"
)

type test struct {
	ieee, castagnoli uint32
	in               string
}

var golden = []test{
	{0x0, 0x0, ""},
	{0xe8b7be43, 0xc1d04330, "a"},
	{0x9e83486d, 0xe2a22936, "ab"},
	{0x352441c2, 0x364b3fb7, "abc"},
	{0xed82cd11, 0x92c80a31, "abcd"},
	{0x8587d865, 0xc450d697, "abcde"},
	{0x4b8e39ef, 0x53bceff1, "abcdef"},
	{0x312a6aa6, 0xe627f441, "abcdefg"},
	{0xaeef2a50, 0xa9421b7, "abcdefgh"},
	{0x8da988af, 0x2ddc99fc, "abcdefghi"},
	{0x3981703a, 0xe6599437, "abcdefghij"},
	{0x6b9cdfe7, 0xb2cc01fe, "Discard medicine more than two years old."},
	{0xc90ef73f, 0xe28207f, "He who has a shady past knows that nice guys finish last."},
	{0xb902341f, 0xbe93f964, "I wouldn't marry him with a ten foot pole."},
	{0x42080e8, 0x9e3be0c3, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
	{0x154c6d11, 0xf505ef04, "The days of the digital watch are numbered.  -Tom Stoppard"},
	{0x4c418325, 0x85d3dc82, "Nepal premier won't resign."},
	{0x33955150, 0xc5142380, "For every action there is an equal and opposite government program."},
	{0x26216a4b, 0x75eb77dd, "His money is twice tainted: 'taint yours and 'taint mine."},
	{0x1abbe45e, 0x91ebe9f7, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
	{0xc89a94f7, 0xf0b1168e, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
	{0xab3abe14, 0x572b74e2, "size:  a.out:  bad magic"},
	{0xbab102b6, 0x8a58a6d5, "The major problem is with sendmail.  -Mark Horton"},
	{0x999149d7, 0x9c426c50, "Give me a rock, paper and scissors and I will move the world.  CCFestoon"},
	{0x6d52a33c, 0x735400a4, "If the enemy is within range, then so are you."},
	{0x90631e8d, 0xbec49c95, "It's well we cannot hear the screams/That we create in others' dreams."},
	{0x78309130, 0xa95a2079, "You remind me of a TV show, but that's all right: I watch it anyway."},
	{0x7d0a377f, 0xde2e65c5, "C is as portable as Stonehedge!!"},
	{0x8c79fd79, 0x297a88ed, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
	{0xa20b7167, 0x66ed1d8b, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction.  Lewis-Randall Rule"},
	{0x8e0bb443, 0xdcded527, "How can you write a big system without C++?  -Paul Glick"},
}

// testGoldenIEEE verifies that the given function returns
// correct IEEE checksums.
func testGoldenIEEE(t *testing.T, crcFunc func(b []byte) uint32) {
	for _, g := range golden {
		if crc := crcFunc([]byte(g.in)); crc != g.ieee {
			t.Errorf("IEEE(%s) = 0x%x want 0x%x", g.in, crc, g.ieee)
		}
	}
}

// testGoldenCastagnoli verifies that the given function returns
// correct IEEE checksums.
func testGoldenCastagnoli(t *testing.T, crcFunc func(b []byte) uint32) {
	for _, g := range golden {
		if crc := crcFunc([]byte(g.in)); crc != g.castagnoli {
			t.Errorf("Castagnoli(%s) = 0x%x want 0x%x", g.in, crc, g.castagnoli)
		}
	}
}

// testCrossCheck generates random buffers of various lengths and verifies that
// the two "update" functions return the same result.
func testCrossCheck(t *testing.T, crcFunc1, crcFunc2 func(crc uint32, b []byte) uint32) {
	// The AMD64 implementation has some cutoffs at lengths 168*3=504 and
	// 1344*3=4032. We should make sure lengths around these values are in the
	// list.
	lengths := []int{0, 1, 2, 3, 4, 5, 10, 16, 50, 100, 128,
		500, 501, 502, 503, 504, 505, 512, 1000, 1024, 2000,
		4030, 4031, 4032, 4033, 4036, 4040, 4048, 4096, 5000, 10000}
	for _, length := range lengths {
		p := make([]byte, length)
		_, _ = rand.Read(p)
		crcInit := uint32(rand.Int63())
		crc1 := crcFunc1(crcInit, p)
		crc2 := crcFunc2(crcInit, p)
		if crc1 != crc2 {
			t.Errorf("mismatch: 0x%x vs 0x%x (buffer length %d)", crc1, crc2, length)
		}
	}
}

// TestSimple tests the simple generic algorithm.
func TestSimple(t *testing.T) {
	tab := simpleMakeTable(IEEE)
	testGoldenIEEE(t, func(b []byte) uint32 {
		return simpleUpdate(0, tab, b)
	})

	tab = simpleMakeTable(Castagnoli)
	testGoldenCastagnoli(t, func(b []byte) uint32 {
		return simpleUpdate(0, tab, b)
	})
}

// TestSimple tests the slicing-by-8 algorithm.
func TestSlicing(t *testing.T) {
	tab := slicingMakeTable(IEEE)
	testGoldenIEEE(t, func(b []byte) uint32 {
		return slicingUpdate(0, tab, b)
	})

	tab = slicingMakeTable(Castagnoli)
	testGoldenCastagnoli(t, func(b []byte) uint32 {
		return slicingUpdate(0, tab, b)
	})

	// Cross-check various polys against the simple algorithm.
	for _, poly := range []uint32{IEEE, Castagnoli, Koopman, 0xD5828281} {
		t1 := simpleMakeTable(poly)
		f1 := func(crc uint32, b []byte) uint32 {
			return simpleUpdate(crc, t1, b)
		}
		t2 := slicingMakeTable(poly)
		f2 := func(crc uint32, b []byte) uint32 {
			return slicingUpdate(crc, t2, b)
		}
		testCrossCheck(t, f1, f2)
	}
}

func TestArchIEEE(t *testing.T) {
	if !archAvailableIEEE() {
		t.Skip("Arch-specific IEEE not available.")
	}
	archInitIEEE()
	slicingTable := slicingMakeTable(IEEE)
	testCrossCheck(t, archUpdateIEEE, func(crc uint32, b []byte) uint32 {
		return slicingUpdate(crc, slicingTable, b)
	})
}

func TestArchCastagnoli(t *testing.T) {
	if !archAvailableCastagnoli() {
		t.Skip("Arch-specific Castagnoli not available.")
	}
	archInitCastagnoli()
	slicingTable := slicingMakeTable(Castagnoli)
	testCrossCheck(t, archUpdateCastagnoli, func(crc uint32, b []byte) uint32 {
		return slicingUpdate(crc, slicingTable, b)
	})
}

func TestGolden(t *testing.T) {
	testGoldenIEEE(t, ChecksumIEEE)

	// Some implementations have special code to deal with misaligned
	// data; test that as well.
	for delta := 1; delta <= 7; delta++ {
		testGoldenIEEE(t, func(b []byte) uint32 {
			ieee := NewIEEE()
			d := delta
			if d >= len(b) {
				d = len(b)
			}
			ieee.Write(b[:d])
			ieee.Write(b[d:])
			return ieee.Sum32()
		})
	}

	castagnoliTab := MakeTable(Castagnoli)
	if castagnoliTab == nil {
		t.Errorf("nil Castagnoli Table")
	}

	testGoldenCastagnoli(t, func(b []byte) uint32 {
		castagnoli := New(castagnoliTab)
		castagnoli.Write(b)
		return castagnoli.Sum32()
	})

	// Some implementations have special code to deal with misaligned
	// data; test that as well.
	for delta := 1; delta <= 7; delta++ {
		testGoldenCastagnoli(t, func(b []byte) uint32 {
			castagnoli := New(castagnoliTab)
			d := delta
			if d >= len(b) {
				d = len(b)
			}
			castagnoli.Write(b[:d])
			castagnoli.Write(b[d:])
			return castagnoli.Sum32()
		})
	}
}

func BenchmarkIEEECrc40B(b *testing.B) {
	benchmark(b, NewIEEE(), 40, 0)
}

func BenchmarkIEEECrc1KB(b *testing.B) {
	benchmark(b, NewIEEE(), 1<<10, 0)
}

func BenchmarkIEEECrc4KB(b *testing.B) {
	benchmark(b, NewIEEE(), 4<<10, 0)
}

func BenchmarkIEEECrc32KB(b *testing.B) {
	benchmark(b, NewIEEE(), 32<<10, 0)
}

func BenchmarkCastagnoliCrc15B(b *testing.B) {
	benchmark(b, New(MakeTable(Castagnoli)), 15, 0)
}

func BenchmarkCastagnoliCrc15BMisaligned(b *testing.B) {
	benchmark(b, New(MakeTable(Castagnoli)), 15, 1)
}

func BenchmarkCastagnoliCrc40B(b *testing.B) {
	benchmark(b, New(MakeTable(Castagnoli)), 40, 0)
}

func BenchmarkCastagnoliCrc40BMisaligned(b *testing.B) {
	benchmark(b, New(MakeTable(Castagnoli)), 40, 1)
}

func BenchmarkCastagnoliCrc512(b *testing.B) {
	benchmark(b, New(MakeTable(Castagnoli)), 512, 0)
}

func BenchmarkCastagnoliCrc512Misaligned(b *testing.B) {
	benchmark(b, New(MakeTable(Castagnoli)), 512, 1)
}

func BenchmarkCastagnoliCrc1KB(b *testing.B) {
	benchmark(b, New(MakeTable(Castagnoli)), 1<<10, 0)
}

func BenchmarkCastagnoliCrc1KBMisaligned(b *testing.B) {
	benchmark(b, New(MakeTable(Castagnoli)), 1<<10, 1)
}

func BenchmarkCastagnoliCrc4KB(b *testing.B) {
	benchmark(b, New(MakeTable(Castagnoli)), 4<<10, 0)
}

func BenchmarkCastagnoliCrc4KBMisaligned(b *testing.B) {
	benchmark(b, New(MakeTable(Castagnoli)), 4<<10, 1)
}

func BenchmarkCastagnoliCrc32KB(b *testing.B) {
	benchmark(b, New(MakeTable(Castagnoli)), 32<<10, 0)
}

func BenchmarkCastagnoliCrc32KBMisaligned(b *testing.B) {
	benchmark(b, New(MakeTable(Castagnoli)), 32<<10, 1)
}

func benchmark(b *testing.B, h hash.Hash32, n, alignment int64) {
	b.SetBytes(n)
	data := make([]byte, n+alignment)
	data = data[alignment:]
	for i := range data {
		data[i] = byte(i)
	}
	in := make([]byte, 0, h.Size())

	// Warm up
	h.Reset()
	h.Write(data)
	h.Sum(in)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		h.Reset()
		h.Write(data)
		h.Sum(in)
	}
}
<commit_msg>hash/crc32: use sub-benchmarks<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package crc32

import (
	"fmt"
	"hash"
	"math/rand"
	"testing"
)

type test struct {
	ieee, castagnoli uint32
	in               string
}

var golden = []test{
	{0x0, 0x0, ""},
	{0xe8b7be43, 0xc1d04330, "a"},
	{0x9e83486d, 0xe2a22936, "ab"},
	{0x352441c2, 0x364b3fb7, "abc"},
	{0xed82cd11, 0x92c80a31, "abcd"},
	{0x8587d865, 0xc450d697, "abcde"},
	{0x4b8e39ef, 0x53bceff1, "abcdef"},
	{0x312a6aa6, 0xe627f441, "abcdefg"},
	{0xaeef2a50, 0xa9421b7, "abcdefgh"},
	{0x8da988af, 0x2ddc99fc, "abcdefghi"},
	{0x3981703a, 0xe6599437, "abcdefghij"},
	{0x6b9cdfe7, 0xb2cc01fe, "Discard medicine more than two years old."},
	{0xc90ef73f, 0xe28207f, "He who has a shady past knows that nice guys finish last."},
	{0xb902341f, 0xbe93f964, "I wouldn't marry him with a ten foot pole."},
	{0x42080e8, 0x9e3be0c3, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
	{0x154c6d11, 0xf505ef04, "The days of the digital watch are numbered.  -Tom Stoppard"},
	{0x4c418325, 0x85d3dc82, "Nepal premier won't resign."},
	{0x33955150, 0xc5142380, "For every action there is an equal and opposite government program."},
	{0x26216a4b, 0x75eb77dd, "His money is twice tainted: 'taint yours and 'taint mine."},
	{0x1abbe45e, 0x91ebe9f7, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
	{0xc89a94f7, 0xf0b1168e, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
	{0xab3abe14, 0x572b74e2, "size:  a.out:  bad magic"},
	{0xbab102b6, 0x8a58a6d5, "The major problem is with sendmail.  -Mark Horton"},
	{0x999149d7, 0x9c426c50, "Give me a rock, paper and scissors and I will move the world.  CCFestoon"},
	{0x6d52a33c, 0x735400a4, "If the enemy is within range, then so are you."},
	{0x90631e8d, 0xbec49c95, "It's well we cannot hear the screams/That we create in others' dreams."},
	{0x78309130, 0xa95a2079, "You remind me of a TV show, but that's all right: I watch it anyway."},
	{0x7d0a377f, 0xde2e65c5, "C is as portable as Stonehedge!!"},
	{0x8c79fd79, 0x297a88ed, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
	{0xa20b7167, 0x66ed1d8b, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction.  Lewis-Randall Rule"},
	{0x8e0bb443, 0xdcded527, "How can you write a big system without C++?  -Paul Glick"},
}

// testGoldenIEEE verifies that the given function returns
// correct IEEE checksums.
func testGoldenIEEE(t *testing.T, crcFunc func(b []byte) uint32) {
	for _, g := range golden {
		if crc := crcFunc([]byte(g.in)); crc != g.ieee {
			t.Errorf("IEEE(%s) = 0x%x want 0x%x", g.in, crc, g.ieee)
		}
	}
}

// testGoldenCastagnoli verifies that the given function returns
// correct IEEE checksums.
func testGoldenCastagnoli(t *testing.T, crcFunc func(b []byte) uint32) {
	for _, g := range golden {
		if crc := crcFunc([]byte(g.in)); crc != g.castagnoli {
			t.Errorf("Castagnoli(%s) = 0x%x want 0x%x", g.in, crc, g.castagnoli)
		}
	}
}

// testCrossCheck generates random buffers of various lengths and verifies that
// the two "update" functions return the same result.
func testCrossCheck(t *testing.T, crcFunc1, crcFunc2 func(crc uint32, b []byte) uint32) {
	// The AMD64 implementation has some cutoffs at lengths 168*3=504 and
	// 1344*3=4032. We should make sure lengths around these values are in the
	// list.
	lengths := []int{0, 1, 2, 3, 4, 5, 10, 16, 50, 100, 128,
		500, 501, 502, 503, 504, 505, 512, 1000, 1024, 2000,
		4030, 4031, 4032, 4033, 4036, 4040, 4048, 4096, 5000, 10000}
	for _, length := range lengths {
		p := make([]byte, length)
		_, _ = rand.Read(p)
		crcInit := uint32(rand.Int63())
		crc1 := crcFunc1(crcInit, p)
		crc2 := crcFunc2(crcInit, p)
		if crc1 != crc2 {
			t.Errorf("mismatch: 0x%x vs 0x%x (buffer length %d)", crc1, crc2, length)
		}
	}
}

// TestSimple tests the simple generic algorithm.
func TestSimple(t *testing.T) {
	tab := simpleMakeTable(IEEE)
	testGoldenIEEE(t, func(b []byte) uint32 {
		return simpleUpdate(0, tab, b)
	})

	tab = simpleMakeTable(Castagnoli)
	testGoldenCastagnoli(t, func(b []byte) uint32 {
		return simpleUpdate(0, tab, b)
	})
}

// TestSimple tests the slicing-by-8 algorithm.
func TestSlicing(t *testing.T) {
	tab := slicingMakeTable(IEEE)
	testGoldenIEEE(t, func(b []byte) uint32 {
		return slicingUpdate(0, tab, b)
	})

	tab = slicingMakeTable(Castagnoli)
	testGoldenCastagnoli(t, func(b []byte) uint32 {
		return slicingUpdate(0, tab, b)
	})

	// Cross-check various polys against the simple algorithm.
	for _, poly := range []uint32{IEEE, Castagnoli, Koopman, 0xD5828281} {
		t1 := simpleMakeTable(poly)
		f1 := func(crc uint32, b []byte) uint32 {
			return simpleUpdate(crc, t1, b)
		}
		t2 := slicingMakeTable(poly)
		f2 := func(crc uint32, b []byte) uint32 {
			return slicingUpdate(crc, t2, b)
		}
		testCrossCheck(t, f1, f2)
	}
}

func TestArchIEEE(t *testing.T) {
	if !archAvailableIEEE() {
		t.Skip("Arch-specific IEEE not available.")
	}
	archInitIEEE()
	slicingTable := slicingMakeTable(IEEE)
	testCrossCheck(t, archUpdateIEEE, func(crc uint32, b []byte) uint32 {
		return slicingUpdate(crc, slicingTable, b)
	})
}

func TestArchCastagnoli(t *testing.T) {
	if !archAvailableCastagnoli() {
		t.Skip("Arch-specific Castagnoli not available.")
	}
	archInitCastagnoli()
	slicingTable := slicingMakeTable(Castagnoli)
	testCrossCheck(t, archUpdateCastagnoli, func(crc uint32, b []byte) uint32 {
		return slicingUpdate(crc, slicingTable, b)
	})
}

func TestGolden(t *testing.T) {
	testGoldenIEEE(t, ChecksumIEEE)

	// Some implementations have special code to deal with misaligned
	// data; test that as well.
	for delta := 1; delta <= 7; delta++ {
		testGoldenIEEE(t, func(b []byte) uint32 {
			ieee := NewIEEE()
			d := delta
			if d >= len(b) {
				d = len(b)
			}
			ieee.Write(b[:d])
			ieee.Write(b[d:])
			return ieee.Sum32()
		})
	}

	castagnoliTab := MakeTable(Castagnoli)
	if castagnoliTab == nil {
		t.Errorf("nil Castagnoli Table")
	}

	testGoldenCastagnoli(t, func(b []byte) uint32 {
		castagnoli := New(castagnoliTab)
		castagnoli.Write(b)
		return castagnoli.Sum32()
	})

	// Some implementations have special code to deal with misaligned
	// data; test that as well.
	for delta := 1; delta <= 7; delta++ {
		testGoldenCastagnoli(t, func(b []byte) uint32 {
			castagnoli := New(castagnoliTab)
			d := delta
			if d >= len(b) {
				d = len(b)
			}
			castagnoli.Write(b[:d])
			castagnoli.Write(b[d:])
			return castagnoli.Sum32()
		})
	}
}

func BenchmarkCRC32(b *testing.B) {
	b.Run("poly=IEEE", benchmarkAll(NewIEEE()))
	b.Run("poly=Castagnoli", benchmarkAll(New(MakeTable(Castagnoli))))
	b.Run("poly=Koopman", benchmarkAll(New(MakeTable(Koopman))))
}

func benchmarkAll(h hash.Hash32) func(b *testing.B) {
	return func(b *testing.B) {
		for _, size := range []int{15, 40, 512, 1 << 10, 4 << 10, 32 << 10} {
			name := fmt.Sprint(size)
			if size >= 1024 {
				name = fmt.Sprintf("%dkB", size/1024)
			}
			b.Run("size="+name, func(b *testing.B) {
				for align := 0; align <= 1; align++ {
					b.Run(fmt.Sprintf("align=%d", align), func(b *testing.B) {
						benchmark(b, h, int64(size), int64(align))
					})
				}
			})
		}
	}
}

func benchmark(b *testing.B, h hash.Hash32, n, alignment int64) {
	b.SetBytes(n)
	data := make([]byte, n+alignment)
	data = data[alignment:]
	for i := range data {
		data[i] = byte(i)
	}
	in := make([]byte, 0, h.Size())

	// Warm up
	h.Reset()
	h.Write(data)
	h.Sum(in)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		h.Reset()
		h.Write(data)
		h.Sum(in)
	}
}
<|endoftext|>


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

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

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

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

package e2e

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

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"

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

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

	totalPods := len(nodes.Items)

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

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

var _ = Describe("Networking", func() {
	f := NewFramework("nettest")

	var svcname = "nettest"

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

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

	//Now we can proceed with the test.
	It("should function for intra-pod communication", func(done Done) {
		defer close(done)

		if testContext.Provider == "vagrant" {
			By("Skipping test which is broken for vagrant (See https://github.com/GoogleCloudPlatform/kubernetes/issues/3580)")
			return
		}

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

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

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

		nodes, err := f.Client.Nodes().List(labels.Everything(), fields.Everything())
		if err != nil {
			Failf("Failed to list nodes: %v", err)
		}

		podNames := LaunchNetTestPodPerNode(f, nodes, svcname)

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

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

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

		//once response OK, evaluate response body for pass/fail.
		var body []byte
		getDetails := func() ([]byte, error) {
			return f.Client.Get().
				Namespace(f.Namespace.Name).
				Prefix("proxy").
				Resource("services").
				Name(svc.Name).
				Suffix("read").
				DoRaw()
		}

		getStatus := func() ([]byte, error) {
			return f.Client.Get().
				Namespace(f.Namespace.Name).
				Prefix("proxy").
				Resource("services").
				Name(svc.Name).
				Suffix("status").
				DoRaw()
		}

		for i := 0; !passed; i++ { // Timeout will keep us from going forever.
			time.Sleep(2 * time.Second)
			Logf("About to make a proxy status call")
			start := time.Now()
			body, err = getStatus()
			Logf("Proxy status call returned in %v", time.Since(start))
			if err != nil {
				Logf("Attempt %v: service/pod still starting. (error: '%v')", i, err)
				continue
			}
			// Finally, we pass/fail the test based on if the container's response body, as to wether or not it was able to find peers.
			switch {
			case string(body) == "pass":
				Logf("Passed on attempt %v. Cleaning up.", i)
				passed = true
			case string(body) == "running":
				Logf("Attempt %v: test still running", i)
			case string(body) == "fail":
				if body, err = getDetails(); err != nil {
					Failf("Failed on attempt %v. Cleaning up. Error reading details: %v", i, err)
				} else {
					Failf("Failed on attempt %v. Cleaning up. Details:\n%s", i, string(body))
				}
			case strings.Contains(string(body), "no endpoints available"):
				Logf("Attempt %v: waiting on service/endpoints", i)
			default:
				Logf("Unexpected response:\n%s", body)
			}
		}

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

})
<commit_msg>split into old/new networking test<commit_after>/*
Copyright 2014 The Kubernetes Authors All rights reserved.

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

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

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

package e2e

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

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"

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

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

	totalPods := len(nodes.Items)

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

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

var _ = Describe("NetworkingNew", func() {
	f := NewFramework("nettestnew")

	var svcname = "nettest"

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

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

	//Now we can proceed with the test.
	It("should function for intra-pod communication", func(done Done) {
		defer close(done)

		if testContext.Provider == "vagrant" {
			By("Skipping test which is broken for vagrant (See https://github.com/GoogleCloudPlatform/kubernetes/issues/3580)")
			return
		}

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

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

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

		nodes, err := f.Client.Nodes().List(labels.Everything(), fields.Everything())
		if err != nil {
			Failf("Failed to list nodes: %v", err)
		}

		podNames := LaunchNetTestPodPerNodeNew(f, nodes, svcname)

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

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

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

		//once response OK, evaluate response body for pass/fail.
		var body []byte
		getDetails := func() ([]byte, error) {
			return f.Client.Get().
				Namespace(f.Namespace.Name).
				Prefix("proxy").
				Resource("services").
				Name(svc.Name).
				Suffix("read").
				DoRaw()
		}

		getStatus := func() ([]byte, error) {
			return f.Client.Get().
				Namespace(f.Namespace.Name).
				Prefix("proxy").
				Resource("services").
				Name(svc.Name).
				Suffix("status").
				DoRaw()
		}

		for i := 0; !passed; i++ { // Timeout will keep us from going forever.
			time.Sleep(2 * time.Second)
			Logf("About to make a proxy status call")
			start := time.Now()
			body, err = getStatus()
			Logf("Proxy status call returned in %v", time.Since(start))
			if err != nil {
				Logf("Attempt %v: service/pod still starting. (error: '%v')", i, err)
				continue
			}
			// Finally, we pass/fail the test based on if the container's response body, as to wether or not it was able to find peers.
			switch {
			case string(body) == "pass":
				Logf("Passed on attempt %v. Cleaning up.", i)
				passed = true
			case string(body) == "running":
				Logf("Attempt %v: test still running", i)
			case string(body) == "fail":
				if body, err = getDetails(); err != nil {
					Failf("Failed on attempt %v. Cleaning up. Error reading details: %v", i, err)
				} else {
					Failf("Failed on attempt %v. Cleaning up. Details:\n%s", i, string(body))
				}
			case strings.Contains(string(body), "no endpoints available"):
				Logf("Attempt %v: waiting on service/endpoints", i)
			default:
				Logf("Unexpected response:\n%s", body)
			}
		}

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

})

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

	totalPods := len(nodes.Items)

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

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

var _ = Describe("Networking", func() {
	f := NewFramework("nettest")

	var svcname = "nettest"

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

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

	//Now we can proceed with the test.
	It("should function for intra-pod communication", func(done Done) {
		defer close(done)

		if testContext.Provider == "vagrant" {
			By("Skipping test which is broken for vagrant (See https://github.com/GoogleCloudPlatform/kubernetes/issues/3580)")
			return
		}

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

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

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

		nodes, err := f.Client.Nodes().List(labels.Everything(), fields.Everything())
		if err != nil {
			Failf("Failed to list nodes: %v", err)
		}

		podNames := LaunchNetTestPodPerNode(f, nodes, svcname)

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

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

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

		//once response OK, evaluate response body for pass/fail.
		var body []byte
		getDetails := func() ([]byte, error) {
			return f.Client.Get().
				Namespace(f.Namespace.Name).
				Prefix("proxy").
				Resource("services").
				Name(svc.Name).
				Suffix("read").
				DoRaw()
		}

		getStatus := func() ([]byte, error) {
			return f.Client.Get().
				Namespace(f.Namespace.Name).
				Prefix("proxy").
				Resource("services").
				Name(svc.Name).
				Suffix("status").
				DoRaw()
		}

		for i := 0; !passed; i++ { // Timeout will keep us from going forever.
			time.Sleep(2 * time.Second)
			Logf("About to make a proxy status call")
			start := time.Now()
			body, err = getStatus()
			Logf("Proxy status call returned in %v", time.Since(start))
			if err != nil {
				Logf("Attempt %v: service/pod still starting. (error: '%v')", i, err)
				continue
			}
			// Finally, we pass/fail the test based on if the container's response body, as to wether or not it was able to find peers.
			switch {
			case string(body) == "pass":
				Logf("Passed on attempt %v. Cleaning up.", i)
				passed = true
			case string(body) == "running":
				Logf("Attempt %v: test still running", i)
			case string(body) == "fail":
				if body, err = getDetails(); err != nil {
					Failf("Failed on attempt %v. Cleaning up. Error reading details: %v", i, err)
				} else {
					Failf("Failed on attempt %v. Cleaning up. Details:\n%s", i, string(body))
				}
			case strings.Contains(string(body), "no endpoints available"):
				Logf("Attempt %v: waiting on service/endpoints", i)
			default:
				Logf("Unexpected response:\n%s", body)
			}
		}

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

})
<|endoftext|>


<commit_before>/*
Copyright 2014 Google Inc. All rights reserved.

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

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

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

package e2e

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

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"

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

var _ = BeforeSuite(func() {
	//Assert basic external connectivity.
	//Since this is not really a test of kubernetes in any way, we
	//leave it as a pre-test assertion, rather than a Ginko test.

	By("Executing a successfull http request from the external internet")
	resp, err := http.Get("http://google.com")
	if err != nil {
		Failf("Unable to connect/talk to the internet: %v", err)
	}
	if resp.StatusCode != http.StatusOK {
		Failf("Unexpected error code, expected 200, got, %v (%v)", resp.StatusCode, resp)
	}
})

func LaunchNetTestPodPerNode(nodes *api.NodeList, name string, c *client.Client, ns string) []string {
	podNames := []string{}

	totalPods := len(nodes.Items)

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

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

var _ = Describe("Networking", func() {
	var c *client.Client

	BeforeEach(func() {
		var err error
		c, err = loadClient()
		Expect(err).NotTo(HaveOccurred())
	})

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

	// Create a unique namespace for this test.
	ns := "nettest-" + randomSuffix()
	name := "nettest"

	It("should function for intra-pod communication", func() {
		if testContext.Provider == "vagrant" {
			By("Skipping test which is broken for vagrant (See https://github.com/GoogleCloudPlatform/kubernetes/issues/3580)")
			return
		}

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

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

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

		nodes, err := c.Nodes().List()
		if err != nil {
			Failf("Failed to list nodes: %v", err)
		}

		podNames := LaunchNetTestPodPerNode(nodes, name, c, ns)

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

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

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

		//once response OK, evaluate response body for pass/fail.
		var body []byte

		for i := 0; i < maxAttempts && !passed; i++ {
			time.Sleep(2 * time.Second)
			Logf("About to make a proxy status call")
			start := time.Now()
			body, err = c.Get().
				Namespace(ns).
				Prefix("proxy").
				Resource("services").
				Name(svc.Name).
				Suffix("status").
				DoRaw()
			Logf("Proxy status call returned in %v", time.Since(start))
			if err != nil {
				Logf("Attempt %v/%v: service/pod still starting. (error: '%v')", i, maxAttempts, err)
				continue
			}
			//Finally, we pass/fail the test based on if the container's response body, as to wether or not it was able to find peers.
			switch string(body) {
			case "pass":
				Logf("Passed on attempt %v. Cleaning up.", i)
				passed = true
				break
			case "running":
				Logf("Attempt %v/%v: test still running", i, maxAttempts)
				break
			case "fail":
				if body, err = c.Get().
					Namespace(ns).Prefix("proxy").
					Resource("services").
					Name(svc.Name).Suffix("read").
					DoRaw(); err != nil {
					Failf("Failed on attempt %v. Cleaning up. Error reading details: %v", i, err)
				} else {
					Failf("Failed on attempt %v. Cleaning up. Details:\n%s", i, string(body))
				}
				break
			}
		}

		if !passed {
			if body, err = c.Get().
				Namespace(ns).
				Prefix("proxy").
				Resource("services").
				Name(svc.Name).
				Suffix("read").
				DoRaw(); err != nil {
				Failf("Timed out. Cleaning up. Error reading details: %v", err)
			} else {
				Failf("Timed out. Cleaning up. Details:\n%s", string(body))
			}
		}
		Expect(string(body)).To(Equal("pass"))
	})

})
<commit_msg>Add a ephemeral namespace to networking.go, to be generalized shortly hereafter.<commit_after>/*
Copyright 2014 Google Inc. All rights reserved.

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

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

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

package e2e

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

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"

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

//Namespace constants, implemented
var svcname = "nettest"
var ns = svcname + "-" + randomSuffix()
var c *client.Client = nil
var namespaceObj *api.Namespace

var _ = BeforeSuite(func() {
	//Assert basic external connectivity.
	//Since this is not really a test of kubernetes in any way, we
	//leave it as a pre-test assertion, rather than a Ginko test.

	By("Executing a successfull http request from the external internet")
	resp, err := http.Get("http://google.com")
	if err != nil {
		Failf("Unable to connect/talk to the internet: %v", err)
	}
	if resp.StatusCode != http.StatusOK {
		Failf("Unexpected error code, expected 200, got, %v (%v)", resp.StatusCode, resp)
	}

	By("Building a namespace api object")
	namespaceObj = &api.Namespace{
		ObjectMeta: api.ObjectMeta{
			Name:      ns,
			Namespace: "",
		},
		Status: api.NamespaceStatus{},
	}

	By("Creating a kubernetes client")
	c, err = loadClient()
	Expect(err).NotTo(HaveOccurred())

	By("Creating a namespace for this test suite")
	_, err = c.Namespaces().Create(namespaceObj)
	Expect(err).NotTo(HaveOccurred())

})

var _ = AfterSuite(func() {
	By("Destroying namespace for this suite")
	err := c.Namespaces().Delete(namespaceObj.ObjectMeta.Name)
	if err != nil && !errors.IsAlreadyExists(err) {
		Failf("Couldng make ns %s", err)
	}

})

func LaunchNetTestPodPerNode(nodes *api.NodeList, name string, c *client.Client, ns string) []string {
	podNames := []string{}

	totalPods := len(nodes.Items)

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

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

var _ = Describe("Networking", func() {
	//var c *client.Client

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

	// Create a unique namespace for this test.
	ns := "nettest-" + randomSuffix()

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

		if testContext.Provider == "vagrant" {
			By("Skipping test which is broken for vagrant (See https://github.com/GoogleCloudPlatform/kubernetes/issues/3580)")
			return
		}

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

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

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

		nodes, err := c.Nodes().List()
		if err != nil {
			Failf("Failed to list nodes: %v", err)
		}

		podNames := LaunchNetTestPodPerNode(nodes, svcname, c, ns)

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

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

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

		//once response OK, evaluate response body for pass/fail.
		var body []byte

		for i := 0; i < maxAttempts && !passed; i++ {
			time.Sleep(2 * time.Second)
			Logf("About to make a proxy status call")
			start := time.Now()
			body, err = c.Get().
				Namespace(ns).
				Prefix("proxy").
				Resource("services").
				Name(svc.Name).
				Suffix("status").
				DoRaw()
			Logf("Proxy status call returned in %v", time.Since(start))
			if err != nil {
				Logf("Attempt %v/%v: service/pod still starting. (error: '%v')", i, maxAttempts, err)
				continue
			}
			//Finally, we pass/fail the test based on if the container's response body, as to wether or not it was able to find peers.
			switch string(body) {
			case "pass":
				Logf("Passed on attempt %v. Cleaning up.", i)
				passed = true
				break
			case "running":
				Logf("Attempt %v/%v: test still running", i, maxAttempts)
				break
			case "fail":
				if body, err = c.Get().
					Namespace(ns).Prefix("proxy").
					Resource("services").
					Name(svc.Name).Suffix("read").
					DoRaw(); err != nil {
					Failf("Failed on attempt %v. Cleaning up. Error reading details: %v", i, err)
				} else {
					Failf("Failed on attempt %v. Cleaning up. Details:\n%s", i, string(body))
				}
				break
			}
		}

		if !passed {
			if body, err = c.Get().
				Namespace(ns).
				Prefix("proxy").
				Resource("services").
				Name(svc.Name).
				Suffix("read").
				DoRaw(); err != nil {
				Failf("Timed out. Cleaning up. Error reading details: %v", err)
			} else {
				Failf("Timed out. Cleaning up. Details:\n%s", string(body))
			}
		}
		Expect(string(body)).To(Equal("pass"))
	})

})
<|endoftext|>


<commit_before>package auth

import (
	"context"
	"fmt"
	"os"
	"strings"
	"text/tabwriter"

	"github.com/micro/cli/v2"
	pb "github.com/micro/go-micro/v2/auth/service/proto"
	"github.com/micro/go-micro/v2/client"
)

func listRules(ctx *cli.Context) {
	client := rulesFromContext(ctx)

	rsp, err := client.List(context.TODO(), &pb.ListRequest{})
	if err != nil {
		fmt.Printf("Error listing rules: %v\n", err)
		os.Exit(1)
	}

	w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0)
	defer w.Flush()

	fmt.Fprintln(w, strings.Join([]string{"Role", "Access", "Resource", "Priority"}, "\t"))
	for _, r := range rsp.Rules {
		res := strings.Join([]string{r.Resource.Namespace, r.Resource.Type, r.Resource.Name, r.Resource.Endpoint}, ":")
		fmt.Fprintln(w, strings.Join([]string{r.Role, r.Access.String(), res, fmt.Sprintf("%b", r.Priority)}, "\t"))
	}
}

func createRule(ctx *cli.Context) {
	client := rulesFromContext(ctx)
	r := constructRule(ctx)

	_, err := client.Create(context.TODO(), &pb.CreateRequest{
		Role:     r.Role,
		Access:   r.Access,
		Resource: r.Resource,
		Priority: r.Priority,
	})
	if err != nil {
		fmt.Printf("Error creating rule: %v\n", err)
		os.Exit(1)
	}

	fmt.Println("Rule created")
}

func deleteRule(ctx *cli.Context) {
	client := rulesFromContext(ctx)
	r := constructRule(ctx)

	_, err := client.Delete(context.TODO(), &pb.DeleteRequest{
		Role:     r.Role,
		Access:   r.Access,
		Resource: r.Resource,
		Priority: r.Priority,
	})
	if err != nil {
		fmt.Printf("Error creating rule: %v\n", err)
		os.Exit(1)
	}

	fmt.Println("Rule deleted")
}

func constructRule(ctx *cli.Context) *pb.Rule {
	var access pb.Access
	switch ctx.String("access") {
	case "granted":
		access = pb.Access_GRANTED
	case "denied":
		access = pb.Access_DENIED
	default:
		fmt.Printf("Invalid access: %v, must be granted or denied\n", ctx.String("access"))
		os.Exit(1)
	}

	resComps := strings.Split(ctx.String("resource"), ":")
	if len(resComps) != 4 {
		fmt.Println("Invalid resource, must be in the format namespace:type:name:endpoint")
	}

	return &pb.Rule{
		Access:   access,
		Role:     ctx.String("role"),
		Priority: int32(ctx.Int("priority")),
		Resource: &pb.Resource{
			Namespace: resComps[0],
			Type:      resComps[1],
			Name:      resComps[2],
			Endpoint:  resComps[3],
		},
	}
}

func rulesFromContext(ctx *cli.Context) pb.RulesService {
	if ctx.Bool("platform") {
		os.Setenv("MICRO_PROXY", "service")
		os.Setenv("MICRO_PROXY_ADDRESS", "proxy.micro.mu:443")
	}

	return pb.NewRulesService("go.micro.auth", client.DefaultClient)
}
<commit_msg>Format Auth List Rules (#793)<commit_after>package auth

import (
	"context"
	"fmt"
	"os"
	"sort"
	"strings"
	"text/tabwriter"

	"github.com/micro/cli/v2"
	pb "github.com/micro/go-micro/v2/auth/service/proto"
	"github.com/micro/go-micro/v2/client"
)

func listRules(ctx *cli.Context) {
	client := rulesFromContext(ctx)

	rsp, err := client.List(context.TODO(), &pb.ListRequest{})
	if err != nil {
		fmt.Printf("Error listing rules: %v\n", err)
		os.Exit(1)
	}

	w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0)
	defer w.Flush()

	formatResource := func(r *pb.Resource) string {
		return strings.Join([]string{r.Namespace, r.Type, r.Name, r.Endpoint}, ":")
	}

	// sort rules using resource name and priority to keep the list consistent
	sort.Slice(rsp.Rules, func(i, j int) bool {
		resI := formatResource(rsp.Rules[i].Resource) + string(rsp.Rules[i].Priority)
		resJ := formatResource(rsp.Rules[j].Resource) + string(rsp.Rules[j].Priority)
		return sort.StringsAreSorted([]string{resJ, resI})
	})

	fmt.Fprintln(w, strings.Join([]string{"Role", "Access", "Resource", "Priority"}, "\t"))
	for _, r := range rsp.Rules {
		res := formatResource(r.Resource)
		fmt.Fprintln(w, strings.Join([]string{r.Role, r.Access.String(), res, fmt.Sprintf("%d", r.Priority)}, "\t"))
	}
}

func createRule(ctx *cli.Context) {
	client := rulesFromContext(ctx)
	r := constructRule(ctx)

	_, err := client.Create(context.TODO(), &pb.CreateRequest{
		Role:     r.Role,
		Access:   r.Access,
		Resource: r.Resource,
		Priority: r.Priority,
	})
	if err != nil {
		fmt.Printf("Error creating rule: %v\n", err)
		os.Exit(1)
	}

	fmt.Println("Rule created")
}

func deleteRule(ctx *cli.Context) {
	client := rulesFromContext(ctx)
	r := constructRule(ctx)

	_, err := client.Delete(context.TODO(), &pb.DeleteRequest{
		Role:     r.Role,
		Access:   r.Access,
		Resource: r.Resource,
		Priority: r.Priority,
	})
	if err != nil {
		fmt.Printf("Error creating rule: %v\n", err)
		os.Exit(1)
	}

	fmt.Println("Rule deleted")
}

func constructRule(ctx *cli.Context) *pb.Rule {
	var access pb.Access
	switch ctx.String("access") {
	case "granted":
		access = pb.Access_GRANTED
	case "denied":
		access = pb.Access_DENIED
	default:
		fmt.Printf("Invalid access: %v, must be granted or denied\n", ctx.String("access"))
		os.Exit(1)
	}

	resComps := strings.Split(ctx.String("resource"), ":")
	if len(resComps) != 4 {
		fmt.Println("Invalid resource, must be in the format namespace:type:name:endpoint")
	}

	return &pb.Rule{
		Access:   access,
		Role:     ctx.String("role"),
		Priority: int32(ctx.Int("priority")),
		Resource: &pb.Resource{
			Namespace: resComps[0],
			Type:      resComps[1],
			Name:      resComps[2],
			Endpoint:  resComps[3],
		},
	}
}

func rulesFromContext(ctx *cli.Context) pb.RulesService {
	if ctx.Bool("platform") {
		os.Setenv("MICRO_PROXY", "service")
		os.Setenv("MICRO_PROXY_ADDRESS", "proxy.micro.mu:443")
	}

	return pb.NewRulesService("go.micro.auth", client.DefaultClient)
}
<|endoftext|>


<commit_before>package trace

import "bytes"

// Writer is a test trace writer.
type Writer struct {
	bytes.Buffer
}

func NewWriter() *Writer {
	w := new(Writer)
	w.Write([]byte("go 1.9 trace\x00\x00\x00\x00"))
	return w
}

// Emit writes an event record to the trace.
// See Event types for valid types and required arguments.
func (w *Writer) Emit(typ byte, args ...uint64) {
	nargs := byte(len(args)) - 1
	if nargs > 3 {
		nargs = 3
	}
	buf := []byte{typ | nargs<<6}
	if nargs == 3 {
		buf = append(buf, 0)
	}
	for _, a := range args {
		buf = appendVarint(buf, a)
	}
	if nargs == 3 {
		buf[1] = byte(len(buf) - 2)
	}
	n, err := w.Write(buf)
	if n != len(buf) || err != nil {
		panic("failed to write")
	}
}

func appendVarint(buf []byte, v uint64) []byte {
	for ; v >= 0x80; v >>= 7 {
		buf = append(buf, 0x80|byte(v))
	}
	buf = append(buf, byte(v))
	return buf
}
<commit_msg>internal/trace: add license header to writer.go<commit_after>// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package trace

import "bytes"

// Writer is a test trace writer.
type Writer struct {
	bytes.Buffer
}

func NewWriter() *Writer {
	w := new(Writer)
	w.Write([]byte("go 1.9 trace\x00\x00\x00\x00"))
	return w
}

// Emit writes an event record to the trace.
// See Event types for valid types and required arguments.
func (w *Writer) Emit(typ byte, args ...uint64) {
	nargs := byte(len(args)) - 1
	if nargs > 3 {
		nargs = 3
	}
	buf := []byte{typ | nargs<<6}
	if nargs == 3 {
		buf = append(buf, 0)
	}
	for _, a := range args {
		buf = appendVarint(buf, a)
	}
	if nargs == 3 {
		buf[1] = byte(len(buf) - 2)
	}
	n, err := w.Write(buf)
	if n != len(buf) || err != nil {
		panic("failed to write")
	}
}

func appendVarint(buf []byte, v uint64) []byte {
	for ; v >= 0x80; v >>= 7 {
		buf = append(buf, 0x80|byte(v))
	}
	buf = append(buf, byte(v))
	return buf
}
<|endoftext|>


<commit_before>package entity_test

import (
	"go/build"
	"runtime"
	"service"
	"testing"

	"entity"
)

func init() {
	if runtime.GOOS == "windows" {
		entity.CurSessionModel.Init(build.Default.GOPATH + "\\tmp\\test_curUser.json")
	} else {
		entity.CurSessionModel.Init("/tmp/test_curUser.json")
	}
}

func TestSessionModel(t *testing.T) {
	model := entity.CurSessionModel
	if len(model.GetCurUser()) != 0 {
		t.Error(`Expect no current user at the beginning`)
	}
	model.SetCurUser(&entity.User{
		Username: "test",
	})
	if model.GetCurUser() != "test" {
		t.Errorf(`Expect current user to be '%s'`, "test")
	}
	model.SetCurUser(&entity.User{})
}

func TestSessionService(t *testing.T) {
	err := service.Register("sessionUsername", "testPassword", "email@email.com", "12345678912")
	if err != nil {
		t.Fatal(err)
	}
	if err := service.Login("sessionUsername", "wrongpassword"); err != service.ErrInvalidCredentials {
		t.Fatal(err)
	}
	if err := service.Login("sessionUsername", "testPassword"); err != nil {
		t.Fatal(err)
	}
	if err := service.Logout(); err != nil {
		t.Fatal(err)
	}

	if err := service.Login("sessionUsername", "testPassword"); err != nil {
		t.Fatal(err)
	}
	err = service.DeleteUser()
}
<commit_msg>fix session test<commit_after>package entity_test

import (
	"go/build"
	"runtime"
	"service"
	"testing"

	"entity"
)

func init() {
	if runtime.GOOS == "windows" {
		entity.CurSessionModel.Init(build.Default.GOPATH + "\\tmp\\test_curUser.json")
	} else {
		entity.CurSessionModel.Init("/tmp/test_curUser.json")
	}
}

func TestSessionModel(t *testing.T) {
	model := entity.CurSessionModel
	model.SetCurUser(&entity.User{
		Username: "test",
	})
	if model.GetCurUser() != "test" {
		t.Errorf(`Expect current user to be '%s'`, "test")
	}
	model.SetCurUser(&entity.User{})
}

func TestSessionService(t *testing.T) {
	err := service.Register("sessionUsername", "testPassword", "email@email.com", "12345678912")
	if err != nil {
		t.Fatal(err)
	}
	if err := service.Login("sessionUsername", "wrongpassword"); err != service.ErrInvalidCredentials {
		t.Fatal(err)
	}
	if err := service.Login("sessionUsername", "testPassword"); err != nil {
		t.Fatal(err)
	}
	if err := service.Logout(); err != nil {
		t.Fatal(err)
	}

	if err := service.Login("sessionUsername", "testPassword"); err != nil {
		t.Fatal(err)
	}
	err = service.DeleteUser()
}
<|endoftext|>