func refHostIP(envName string) corev1.EnvVar {
	return corev1.EnvVar{
		Name:  envName,
		Value: "",
		ValueFrom: &corev1.EnvVarSource{
			FieldRef: &corev1.ObjectFieldSelector{
				FieldPath: "status.hostIP",
			},
		},
	}
}
refHostIP is to use the k8s downward API and render the host IP
this is useful in cases where the tracing agent is running as a daemonset
package inject
import (
	"fmt"
	"strconv"
	"strings"
	"github.com/aws/aws-sdk-go/aws"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/resource"
)
const envoyTracingConfigVolumeName = "envoy-tracing-config"
type EnvoyTemplateVariables struct {
	AWSRegion                string
	MeshName                 string
	VirtualGatewayOrNodeName string
	Preview                  string
	EnableSDS                bool
	SdsUdsPath               string
	LogLevel                 string
	AdminAccessPort          int32
	AdminAccessLogFile       string
	PreStopDelay             string
	SidecarImage             string
	EnableXrayTracing        bool
	XrayDaemonPort           int32
	EnableJaegerTracing      bool
	JaegerPort               string
	JaegerAddress            string
	EnableDatadogTracing     bool
	DatadogTracerPort        int32
	DatadogTracerAddress     string
	EnableStatsTags          bool
	EnableStatsD             bool
	StatsDPort               int32
	StatsDAddress            string
	StatsDSocketPath         string
}
func updateEnvMapForEnvoy(vars EnvoyTemplateVariables, env map[string]string, vname string) error {
	env["APPMESH_VIRTUAL_NODE_NAME"] = vname
	env["AWS_REGION"] = vars.AWSRegion
	env["APPMESH_PREVIEW"] = vars.Preview
	env["ENVOY_LOG_LEVEL"] = vars.LogLevel
	if vars.EnableSDS {
		env["APPMESH_SDS_SOCKET_PATH"] = vars.SdsUdsPath
	}
	if vars.AdminAccessPort != 0 {
		env["ENVOY_ADMIN_ACCESS_PORT"] = strconv.Itoa(int(vars.AdminAccessPort))
	}
	if vars.AdminAccessLogFile != "" {
		env["ENVOY_ADMIN_ACCESS_LOG_FILE"] = vars.AdminAccessLogFile
	}
	if vars.EnableXrayTracing {
		env["ENABLE_ENVOY_XRAY_TRACING"] = "1"
		env["XRAY_DAEMON_PORT"] = strconv.Itoa(int(vars.XrayDaemonPort))
	}
	if vars.EnableDatadogTracing {
		env["ENABLE_ENVOY_DATADOG_TRACING"] = "1"
		env["DATADOG_TRACER_PORT"] = strconv.Itoa(int(vars.DatadogTracerPort))
		env["DATADOG_TRACER_ADDRESS"] = vars.DatadogTracerAddress
	}
	if vars.EnableStatsTags {
		env["ENABLE_ENVOY_STATS_TAGS"] = "1"
	}
	if vars.EnableStatsD {
		env["ENABLE_ENVOY_DOG_STATSD"] = "1"
		env["STATSD_PORT"] = strconv.Itoa(int(vars.StatsDPort))
		env["STATSD_ADDRESS"] = vars.StatsDAddress
		if statsDSocketPath := strings.TrimSpace(vars.StatsDSocketPath); statsDSocketPath != "" {
			env["STATSD_SOCKET_PATH"] = statsDSocketPath
		}
	}
	if vars.EnableJaegerTracing {
		env["ENABLE_ENVOY_JAEGER_TRACING"] = "1"
		env["JAEGER_TRACER_PORT"] = vars.JaegerPort
		env["JAEGER_TRACER_ADDRESS"] = vars.JaegerAddress
	}
	return nil
}
func buildEnvoySidecar(vars EnvoyTemplateVariables, env map[string]string) (corev1.Container, error) {
	envoy := corev1.Container{
		Name:  "envoy",
		Image: vars.SidecarImage,
		SecurityContext: &corev1.SecurityContext{
			RunAsUser: aws.Int64(1337),
		},
		Ports: []corev1.ContainerPort{
			{
				Name:          "stats",
				ContainerPort: vars.AdminAccessPort,
				Protocol:      "TCP",
			},
		},
		Lifecycle: &corev1.Lifecycle{
			PostStart: nil,
			PreStop: &corev1.Handler{
				Exec: &corev1.ExecAction{Command: []string{
					"sh", "-c", fmt.Sprintf("sleep %s", vars.PreStopDelay),
				}},
			},
		},
	}
	vname := fmt.Sprintf("mesh/%s/virtualNode/%s", vars.MeshName, vars.VirtualGatewayOrNodeName)
	if err := updateEnvMapForEnvoy(vars, env, vname); err != nil {
		return envoy, err
	}
	envoy.Env = getEnvoyEnv(env)
	return envoy, nil
}
func getEnvoyEnv(env map[string]string) []corev1.EnvVar {
	ev := []corev1.EnvVar{}
	for key, val := range env {
		switch k := key; k {
		case "STATSD_ADDRESS", "DATADOG_TRACER_ADDRESS":
			if val == "ref:status.hostIP" {
				ev = append(ev, refHostIP(key))
			} else {
				ev = append(ev, envVar(key, val))
			}
		default:
			ev = append(ev, envVar(key, val))
		}
	}
	return ev
}
func envoyReadinessProbe(initialDelaySeconds int32, periodSeconds int32, adminAccessPort string) *corev1.Probe {
	envoyReadinessCommand := "curl -s http://localhost:" + adminAccessPort + "/server_info | grep state | grep -q LIVE"
	return &corev1.Probe{
		Handler: corev1.Handler{
			Exec: &corev1.ExecAction{Command: []string{
				"sh", "-c", envoyReadinessCommand,
			}},
		},
		InitialDelaySeconds: initialDelaySeconds,
		TimeoutSeconds: 1,
		PeriodSeconds: periodSeconds,
		SuccessThreshold: 1,
		FailureThreshold: 3,
	}
}
func sidecarResources(cpuRequest, memoryRequest, cpuLimit, memoryLimit string) (corev1.ResourceRequirements, error) {
	resources := corev1.ResourceRequirements{}
	if cpuRequest != "" || memoryRequest != "" {
		requests := corev1.ResourceList{}
		if cpuRequest != "" {
			cr, err := resource.ParseQuantity(cpuRequest)
			if err != nil {
				return resources, err
			}
			requests["cpu"] = cr
		}
		if memoryRequest != "" {
			mr, err := resource.ParseQuantity(memoryRequest)
			if err != nil {
				return resources, err
			}
			requests["memory"] = mr
		}
		resources.Requests = requests
	}
	if cpuLimit != "" || memoryLimit != "" {
		limits := corev1.ResourceList{}
		if cpuLimit != "" {
			cl, err := resource.ParseQuantity(cpuLimit)
			if err != nil {
				return resources, err
			}
			limits["cpu"] = cl
		}
		if memoryLimit != "" {
			ml, err := resource.ParseQuantity(memoryLimit)
			if err != nil {
				return resources, err
			}
			limits["memory"] = ml
		}
		resources.Limits = limits
	}
	return resources, nil
}