func (routes HTTPRouteConfigs) combine() *HTTPRouteConfig {
	out := &HTTPRouteConfig{}
	for port, config := range routes {
		for _, host := range config.VirtualHosts {
			vhost := &VirtualHost{
				Name:   host.Name,
				Routes: host.Routes,
			}
			for _, domain := range host.Domains {
				if port == 80 || strings.Contains(domain, ":") {
					vhost.Domains = append(vhost.Domains, domain)
				}
			}
			if len(vhost.Domains) > 0 {
				out.VirtualHosts = append(out.VirtualHosts, vhost)
			}
		}
	}
	return out.normalize()
}
combine creates a new route config that is the union of all HTTP routes.
note that the virtual hosts without an explicit port suffix (IP:PORT) are stripped
for all routes except the route for port 80.
package envoy
import (
	"sort"
	"strings"
	"time"
	"github.com/golang/glog"
	"github.com/golang/protobuf/ptypes"
	"github.com/golang/protobuf/ptypes/duration"
	"istio.io/pilot/model"
)
const (
	DefaultAccessLog = "/dev/stdout"
	DefaultLbType = LbTypeRoundRobin
	LDSName = "lds"
	RDSName = "rds"
	SDSName = "sds"
	CDSName = "cds"
	RDSAll = "http_proxy"
	VirtualListenerName = "virtual"
	ClusterTypeStrictDNS = "strict_dns"
	ClusterTypeStatic = "static"
	ClusterTypeOriginalDST = "original_dst"
	LbTypeRoundRobin = "round_robin"
	LbTypeLeastRequest = "least_request"
	LbTypeRandom = "random"
	LbTypeOriginalDST = "original_dst_lb"
	ClusterFeatureHTTP2 = "http2"
	HTTPConnectionManager = "http_connection_manager"
	TCPProxyFilter = "tcp_proxy"
	MongoProxyFilter = "mongo_proxy"
	RedisProxyFilter = "redis_proxy"
	RedisDefaultOpTimeout = 30 * time.Second
	WildcardAddress = "0.0.0.0"
	LocalhostAddress = "127.0.0.1"
	EgressTraceOperation = "egress"
	IngressTraceOperation = "ingress"
	ZipkinTraceDriverType = "zipkin"
	ZipkinCollectorCluster = "zipkin"
	ZipkinCollectorEndpoint = "/api/v1/spans"
	router  = "router"
	auto    = "auto"
	decoder = "decoder"
	read    = "read"
	both    = "both"
)
func convertDuration(d *duration.Duration) time.Duration {
	dur, err := ptypes.Duration(d)
	if err != nil {
		glog.Warningf("error converting duration %#v, using 0: %v", d, err)
	}
	return dur
}
func protoDurationToMS(dur *duration.Duration) int64 {
	return int64(convertDuration(dur) / time.Millisecond)
}
type Config struct {
	RootRuntime        *RootRuntime   `json:"runtime,omitempty"`
	Listeners          Listeners      `json:"listeners"`
	LDS                *LDSCluster    `json:"lds,omitempty"`
	Admin              Admin          `json:"admin"`
	ClusterManager     ClusterManager `json:"cluster_manager"`
	StatsdUDPIPAddress string         `json:"statsd_udp_ip_address,omitempty"`
	Tracing            *Tracing       `json:"tracing,omitempty"`
	Hash []byte `json:"-"`
}
type Tracing struct {
	HTTPTracer HTTPTracer `json:"http"`
}
type HTTPTracer struct {
	HTTPTraceDriver HTTPTraceDriver `json:"driver"`
}
type HTTPTraceDriver struct {
	HTTPTraceDriverType   string                `json:"type"`
	HTTPTraceDriverConfig HTTPTraceDriverConfig `json:"config"`
}
type HTTPTraceDriverConfig struct {
	CollectorCluster  string `json:"collector_cluster"`
	CollectorEndpoint string `json:"collector_endpoint"`
}
type RootRuntime struct {
	SymlinkRoot          string `json:"symlink_root"`
	Subdirectory         string `json:"subdirectory"`
	OverrideSubdirectory string `json:"override_subdirectory,omitempty"`
}
type AbortFilter struct {
	Percent    int `json:"abort_percent,omitempty"`
	HTTPStatus int `json:"http_status,omitempty"`
}
type DelayFilter struct {
	Type     string `json:"type,omitempty"`
	Percent  int    `json:"fixed_delay_percent,omitempty"`
	Duration int64  `json:"fixed_duration_ms,omitempty"`
}
type Header struct {
	Name  string `json:"name"`
	Value string `json:"value"`
	Regex bool   `json:"regex,omitempty"`
}
type FilterFaultConfig struct {
	Abort           *AbortFilter `json:"abort,omitempty"`
	Delay           *DelayFilter `json:"delay,omitempty"`
	Headers         Headers      `json:"headers,omitempty"`
	UpstreamCluster string       `json:"upstream_cluster,omitempty"`
}
type FilterRouterConfig struct {
	DynamicStats bool `json:"dynamic_stats,omitempty"`
}
type HTTPFilter struct {
	Type   string      `json:"type"`
	Name   string      `json:"name"`
	Config interface{} `json:"config"`
}
type Runtime struct {
	Key     string `json:"key"`
	Default int    `json:"default"`
}
type Decorator struct {
	Operation string `json:"operation"`
}
type HTTPRoute struct {
	Runtime *Runtime `json:"runtime,omitempty"`
	Path   string `json:"path,omitempty"`
	Prefix string `json:"prefix,omitempty"`
	PrefixRewrite string `json:"prefix_rewrite,omitempty"`
	HostRewrite   string `json:"host_rewrite,omitempty"`
	PathRedirect string `json:"path_redirect,omitempty"`
	HostRedirect string `json:"host_redirect,omitempty"`
	Cluster          string           `json:"cluster,omitempty"`
	WeightedClusters *WeightedCluster `json:"weighted_clusters,omitempty"`
	Headers      Headers           `json:"headers,omitempty"`
	TimeoutMS    int64             `json:"timeout_ms,omitempty"`
	RetryPolicy  *RetryPolicy      `json:"retry_policy,omitempty"`
	OpaqueConfig map[string]string `json:"opaque_config,omitempty"`
	AutoHostRewrite  bool `json:"auto_host_rewrite,omitempty"`
	WebsocketUpgrade bool `json:"use_websocket,omitempty"`
	Decorator *Decorator `json:"decorator,omitempty"`
	clusters Clusters
	faults []*HTTPFilter
}
func (route *HTTPRoute) CatchAll() bool {
	return len(route.Headers) == 0 && route.Path == "" && route.Prefix == "/"
}
func (route *HTTPRoute) CombinePathPrefix(path, prefix string) *HTTPRoute {
	switch {
	case path == "" && route.Path == "" && strings.HasPrefix(route.Prefix, prefix):
		return route
	case path == "" && route.Path == "" && strings.HasPrefix(prefix, route.Prefix):
		route.Prefix = prefix
		return route
	case prefix == "" && route.Prefix == "" && route.Path == path:
		return route
	case path == "" && route.Prefix == "" && strings.HasPrefix(route.Path, prefix):
		return route
	case prefix == "" && route.Path == "" && strings.HasPrefix(path, route.Prefix):
		route.Path = path
		route.Prefix = ""
		return route
	default:
		return nil
	}
}
type RetryPolicy struct {
	Policy          string `json:"retry_on"`  
	NumRetries      int    `json:"num_retries,omitempty"`
	PerTryTimeoutMS int64  `json:"per_try_timeout_ms,omitempty"`
}
type WeightedCluster struct {
	Clusters         []*WeightedClusterEntry `json:"clusters"`
	RuntimeKeyPrefix string                  `json:"runtime_key_prefix,omitempty"`
}
type WeightedClusterEntry struct {
	Name   string `json:"name"`
	Weight int    `json:"weight"`
}
type VirtualHost struct {
	Name    string       `json:"name"`
	Domains []string     `json:"domains"`
	Routes  []*HTTPRoute `json:"routes"`
}
func (host *VirtualHost) clusters() Clusters {
	out := make(Clusters, 0)
	for _, route := range host.Routes {
		out = append(out, route.clusters...)
	}
	return out
}
type HTTPRouteConfig struct {
	VirtualHosts []*VirtualHost `json:"virtual_hosts"`
}
type HTTPRouteConfigs map[int]*HTTPRouteConfig
func (routes HTTPRouteConfigs) EnsurePort(port int) *HTTPRouteConfig {
	config, ok := routes[port]
	if !ok {
		config = &HTTPRouteConfig{}
		routes[port] = config
	}
	return config
}
func (routes HTTPRouteConfigs) clusters() Clusters {
	out := make(Clusters, 0)
	for _, config := range routes {
		out = append(out, config.clusters()...)
	}
	return out
}
func (routes HTTPRouteConfigs) normalize() HTTPRouteConfigs {
	out := make(HTTPRouteConfigs)
	for port, routeConfig := range routes {
		out[port] = routeConfig.normalize()
	}
	return out
}