...

Source file src/github.com/emissary-ingress/emissary/v3/pkg/gateway/gw_transforms.go

Documentation: github.com/emissary-ingress/emissary/v3/pkg/gateway

     1  package gateway
     2  
     3  import (
     4  	// standard library
     5  	"fmt"
     6  
     7  	// third-party libraries
     8  	"github.com/pkg/errors"
     9  	"google.golang.org/protobuf/types/known/anypb"
    10  	"google.golang.org/protobuf/types/known/wrapperspb"
    11  	gw "sigs.k8s.io/gateway-api/apis/v1alpha1"
    12  
    13  	// envoy api v3
    14  	v3core "github.com/emissary-ingress/emissary/v3/pkg/api/envoy/config/core/v3"
    15  	v3listener "github.com/emissary-ingress/emissary/v3/pkg/api/envoy/config/listener/v3"
    16  	v3route "github.com/emissary-ingress/emissary/v3/pkg/api/envoy/config/route/v3"
    17  	v3httpman "github.com/emissary-ingress/emissary/v3/pkg/api/envoy/extensions/filters/network/http_connection_manager/v3"
    18  	v3matcher "github.com/emissary-ingress/emissary/v3/pkg/api/envoy/type/matcher/v3"
    19  
    20  	// envoy control plane
    21  	ecp_wellknown "github.com/emissary-ingress/emissary/v3/pkg/envoy-control-plane/wellknown"
    22  
    23  	// first-party libraries
    24  	"github.com/emissary-ingress/emissary/v3/pkg/kates"
    25  )
    26  
    27  func Compile_Gateway(gateway *gw.Gateway) (*CompiledConfig, error) {
    28  	src := SourceFromResource(gateway)
    29  	var listeners []*CompiledListener
    30  	for idx, l := range gateway.Spec.Listeners {
    31  		name := fmt.Sprintf("%s-%d", getName(gateway), idx)
    32  		listener, err := Compile_Listener(src, l, name)
    33  		if err != nil {
    34  			return nil, err
    35  		}
    36  		listeners = append(listeners, listener)
    37  	}
    38  	return &CompiledConfig{
    39  		CompiledItem: NewCompiledItem(src),
    40  		Listeners:    listeners,
    41  	}, nil
    42  }
    43  
    44  func Compile_Listener(parent Source, lst gw.Listener, name string) (*CompiledListener, error) {
    45  	hcm := &v3httpman.HttpConnectionManager{
    46  		StatPrefix: name,
    47  		HttpFilters: []*v3httpman.HttpFilter{
    48  			{Name: ecp_wellknown.CORS},
    49  			{Name: ecp_wellknown.Router},
    50  		},
    51  		RouteSpecifier: &v3httpman.HttpConnectionManager_Rds{
    52  			Rds: &v3httpman.Rds{
    53  				ConfigSource: &v3core.ConfigSource{
    54  					ConfigSourceSpecifier: &v3core.ConfigSource_Ads{
    55  						Ads: &v3core.AggregatedConfigSource{},
    56  					},
    57  				},
    58  				RouteConfigName: name,
    59  			},
    60  		},
    61  	}
    62  	hcmAny, err := anypb.New(hcm)
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  
    67  	return &CompiledListener{
    68  		CompiledItem: NewCompiledItem(Sourcef("listener %s", lst.Hostname)),
    69  		Listener: &v3listener.Listener{
    70  			Name: name,
    71  			Address: &v3core.Address{Address: &v3core.Address_SocketAddress{SocketAddress: &v3core.SocketAddress{
    72  				Address:       "0.0.0.0",
    73  				PortSpecifier: &v3core.SocketAddress_PortValue{PortValue: uint32(lst.Port)},
    74  			}}},
    75  			FilterChains: []*v3listener.FilterChain{
    76  				{
    77  					Filters: []*v3listener.Filter{
    78  						{
    79  							Name:       ecp_wellknown.HTTPConnectionManager,
    80  							ConfigType: &v3listener.Filter_TypedConfig{TypedConfig: hcmAny},
    81  						},
    82  					},
    83  				},
    84  			},
    85  		},
    86  		Predicate: func(route *CompiledRoute) bool {
    87  			return true
    88  		},
    89  		Domains: []string{"*"},
    90  	}, nil
    91  
    92  }
    93  
    94  func Compile_HTTPRoute(httpRoute *gw.HTTPRoute) (*CompiledConfig, error) {
    95  	src := SourceFromResource(httpRoute)
    96  	clusterRefs := []*ClusterRef{}
    97  	var routes []*v3route.Route
    98  	for idx, rule := range httpRoute.Spec.Rules {
    99  		s := Sourcef("rule %d in %s", idx, src)
   100  		_routes, err := Compile_HTTPRouteRule(s, rule, httpRoute.Namespace, &clusterRefs)
   101  		if err != nil {
   102  			return nil, err
   103  		}
   104  		routes = append(routes, _routes...)
   105  	}
   106  	return &CompiledConfig{
   107  		CompiledItem: NewCompiledItem(src),
   108  		Routes: []*CompiledRoute{
   109  			{
   110  				CompiledItem: CompiledItem{Source: src, Namespace: httpRoute.Namespace},
   111  				HTTPRoute:    httpRoute,
   112  				Routes:       routes,
   113  				ClusterRefs:  clusterRefs,
   114  			},
   115  		},
   116  	}, nil
   117  }
   118  
   119  func Compile_HTTPRouteRule(src Source, rule gw.HTTPRouteRule, namespace string, clusterRefs *[]*ClusterRef) ([]*v3route.Route, error) {
   120  	var clusters []*v3route.WeightedCluster_ClusterWeight
   121  	for idx, fwd := range rule.ForwardTo {
   122  		s := Sourcef("forwardTo %d in %s", idx, src)
   123  		clusters = append(clusters, Compile_HTTPRouteForwardTo(s, fwd, namespace, clusterRefs))
   124  	}
   125  
   126  	wc := &v3route.WeightedCluster{Clusters: clusters}
   127  
   128  	matches, err := Compile_HTTPRouteMatches(rule.Matches)
   129  	if err != nil {
   130  		return nil, err
   131  	}
   132  	var result []*v3route.Route
   133  	for _, match := range matches {
   134  		result = append(result, &v3route.Route{
   135  			Match: match,
   136  			Action: &v3route.Route_Route{Route: &v3route.RouteAction{
   137  				ClusterSpecifier: &v3route.RouteAction_WeightedClusters{WeightedClusters: wc},
   138  			}},
   139  		})
   140  	}
   141  
   142  	return result, err
   143  }
   144  
   145  func Compile_HTTPRouteForwardTo(src Source, forward gw.HTTPRouteForwardTo, namespace string, clusterRefs *[]*ClusterRef) *v3route.WeightedCluster_ClusterWeight {
   146  	suffix := ""
   147  	clusterName := *forward.ServiceName
   148  	if forward.Port != nil {
   149  		suffix = fmt.Sprintf("/%d", *forward.Port)
   150  		clusterName = fmt.Sprintf("%s_%d", *forward.ServiceName, *forward.Port)
   151  	}
   152  
   153  	*clusterRefs = append(*clusterRefs, &ClusterRef{
   154  		CompiledItem: NewCompiledItem(src),
   155  		Name:         clusterName,
   156  		EndpointPath: fmt.Sprintf("k8s/%s/%s%s", namespace, *forward.ServiceName, suffix),
   157  	})
   158  	return &v3route.WeightedCluster_ClusterWeight{
   159  		Name:   clusterName,
   160  		Weight: &wrapperspb.UInt32Value{Value: uint32(forward.Weight)},
   161  	}
   162  }
   163  
   164  func Compile_HTTPRouteMatches(matches []gw.HTTPRouteMatch) ([]*v3route.RouteMatch, error) {
   165  	var result []*v3route.RouteMatch
   166  	for _, match := range matches {
   167  		item, err := Compile_HTTPRouteMatch(match)
   168  		if err != nil {
   169  			return nil, err
   170  		}
   171  		result = append(result, item)
   172  	}
   173  	return result, nil
   174  }
   175  
   176  func Compile_HTTPRouteMatch(match gw.HTTPRouteMatch) (*v3route.RouteMatch, error) {
   177  	headers, err := Compile_HTTPHeaderMatch(match.Headers)
   178  	if err != nil {
   179  		return nil, err
   180  	}
   181  	result := &v3route.RouteMatch{
   182  		Headers: headers,
   183  	}
   184  
   185  	switch match.Path.Type {
   186  	case gw.PathMatchExact:
   187  		result.PathSpecifier = &v3route.RouteMatch_Path{Path: match.Path.Value}
   188  	case gw.PathMatchPrefix:
   189  		result.PathSpecifier = &v3route.RouteMatch_Prefix{Prefix: match.Path.Value}
   190  	case gw.PathMatchRegularExpression:
   191  		result.PathSpecifier = &v3route.RouteMatch_SafeRegex{SafeRegex: regexMatcher(match.Path.Value)}
   192  	case "":
   193  		// no path match, but PathSpecifier is required
   194  		result.PathSpecifier = &v3route.RouteMatch_Prefix{}
   195  	default:
   196  		return nil, errors.Errorf("unknown path match type: %q", match.Path.Type)
   197  	}
   198  
   199  	return result, nil
   200  }
   201  
   202  func Compile_HTTPHeaderMatch(headerMatch *gw.HTTPHeaderMatch) ([]*v3route.HeaderMatcher, error) {
   203  	if headerMatch == nil {
   204  		return nil, nil
   205  	}
   206  
   207  	var result []*v3route.HeaderMatcher
   208  	for hdr, pattern := range headerMatch.Values {
   209  		hm := &v3route.HeaderMatcher{
   210  			Name:        hdr,
   211  			InvertMatch: false,
   212  		}
   213  
   214  		switch headerMatch.Type {
   215  		case gw.HeaderMatchExact:
   216  			hm.HeaderMatchSpecifier = &v3route.HeaderMatcher_ExactMatch{ExactMatch: pattern}
   217  		case gw.HeaderMatchRegularExpression:
   218  			hm.HeaderMatchSpecifier = &v3route.HeaderMatcher_SafeRegexMatch{SafeRegexMatch: regexMatcher(pattern)}
   219  		default:
   220  			return nil, errors.Errorf("unknown header match type: %s", headerMatch.Type)
   221  		}
   222  
   223  		result = append(result, hm)
   224  	}
   225  	return result, nil
   226  }
   227  
   228  func regexMatcher(pattern string) *v3matcher.RegexMatcher {
   229  	return &v3matcher.RegexMatcher{
   230  		EngineType: &v3matcher.RegexMatcher_GoogleRe2{GoogleRe2: &v3matcher.RegexMatcher_GoogleRE2{}},
   231  		Regex:      pattern,
   232  	}
   233  }
   234  
   235  func getName(resource kates.Object) string {
   236  	return fmt.Sprintf("%s-%s", resource.GetNamespace(), resource.GetName())
   237  }
   238  

View as plain text