mirror of
https://github.com/pomerium/pomerium.git
synced 2025-06-22 20:48:10 +02:00
Merge branch 'main' into kralicky/tracing
This commit is contained in:
commit
1ada66ca6b
12 changed files with 954 additions and 819 deletions
|
@ -47,6 +47,7 @@ func ExtAuthzFilter(grpcClientTimeout *durationpb.Duration) *envoy_extensions_fi
|
||||||
func HTTPConnectionManagerFilter(
|
func HTTPConnectionManagerFilter(
|
||||||
httpConnectionManager *envoy_extensions_filters_network_http_connection_manager.HttpConnectionManager,
|
httpConnectionManager *envoy_extensions_filters_network_http_connection_manager.HttpConnectionManager,
|
||||||
) *envoy_config_listener_v3.Filter {
|
) *envoy_config_listener_v3.Filter {
|
||||||
|
applyGlobalHTTPConnectionManagerOptions(httpConnectionManager)
|
||||||
return &envoy_config_listener_v3.Filter{
|
return &envoy_config_listener_v3.Filter{
|
||||||
Name: "envoy.filters.network.http_connection_manager",
|
Name: "envoy.filters.network.http_connection_manager",
|
||||||
ConfigType: &envoy_config_listener_v3.Filter_TypedConfig{
|
ConfigType: &envoy_config_listener_v3.Filter_TypedConfig{
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
envoy_config_core_v3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
|
envoy_config_core_v3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
|
||||||
envoy_config_route_v3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
|
envoy_config_route_v3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
|
||||||
envoy_http_connection_manager "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
|
envoy_http_connection_manager "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
|
||||||
|
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||||
|
|
||||||
"github.com/pomerium/pomerium/config"
|
"github.com/pomerium/pomerium/config"
|
||||||
"github.com/pomerium/pomerium/internal/httputil"
|
"github.com/pomerium/pomerium/internal/httputil"
|
||||||
|
@ -120,3 +121,24 @@ func (b *Builder) buildLocalReplyConfig(
|
||||||
}},
|
}},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func applyGlobalHTTPConnectionManagerOptions(hcm *envoy_http_connection_manager.HttpConnectionManager) {
|
||||||
|
if hcm.InternalAddressConfig == nil {
|
||||||
|
// see doc comment on InternalAddressConfig for details
|
||||||
|
hcm.InternalAddressConfig = &envoy_http_connection_manager.HttpConnectionManager_InternalAddressConfig{
|
||||||
|
CidrRanges: []*envoy_config_core_v3.CidrRange{
|
||||||
|
// localhost
|
||||||
|
{AddressPrefix: "127.0.0.1", PrefixLen: wrapperspb.UInt32(32)},
|
||||||
|
{AddressPrefix: "::1", PrefixLen: wrapperspb.UInt32(128)},
|
||||||
|
|
||||||
|
// RFC1918
|
||||||
|
{AddressPrefix: "10.0.0.0", PrefixLen: wrapperspb.UInt32(8)},
|
||||||
|
{AddressPrefix: "192.168.0.0", PrefixLen: wrapperspb.UInt32(16)},
|
||||||
|
{AddressPrefix: "172.16.0.0", PrefixLen: wrapperspb.UInt32(12)},
|
||||||
|
|
||||||
|
// RFC4193
|
||||||
|
{AddressPrefix: "fd00::", PrefixLen: wrapperspb.UInt32(8)},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ func (b *Builder) buildOutboundListener(cfg *config.Config) (*envoy_config_liste
|
||||||
func (b *Builder) buildOutboundHTTPConnectionManager() *envoy_config_listener_v3.Filter {
|
func (b *Builder) buildOutboundHTTPConnectionManager() *envoy_config_listener_v3.Filter {
|
||||||
rc := b.buildOutboundRouteConfiguration()
|
rc := b.buildOutboundRouteConfiguration()
|
||||||
|
|
||||||
tc := marshalAny(&envoy_http_connection_manager.HttpConnectionManager{
|
return HTTPConnectionManagerFilter(&envoy_http_connection_manager.HttpConnectionManager{
|
||||||
CodecType: envoy_http_connection_manager.HttpConnectionManager_AUTO,
|
CodecType: envoy_http_connection_manager.HttpConnectionManager_AUTO,
|
||||||
StatPrefix: "grpc_egress",
|
StatPrefix: "grpc_egress",
|
||||||
// limit request first byte to last byte time
|
// limit request first byte to last byte time
|
||||||
|
@ -56,13 +56,6 @@ func (b *Builder) buildOutboundHTTPConnectionManager() *envoy_config_listener_v3
|
||||||
HTTPRouterFilter(),
|
HTTPRouterFilter(),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
return &envoy_config_listener_v3.Filter{
|
|
||||||
Name: "envoy.filters.network.http_connection_manager",
|
|
||||||
ConfigType: &envoy_config_listener_v3.Filter_TypedConfig{
|
|
||||||
TypedConfig: tc,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Builder) buildOutboundRouteConfiguration() *envoy_config_route_v3.RouteConfiguration {
|
func (b *Builder) buildOutboundRouteConfiguration() *envoy_config_route_v3.RouteConfiguration {
|
||||||
|
|
|
@ -227,6 +227,34 @@
|
||||||
"spawnUpstreamSpan": true
|
"spawnUpstreamSpan": true
|
||||||
},
|
},
|
||||||
"useRemoteAddress": true,
|
"useRemoteAddress": true,
|
||||||
"xffNumTrustedHops": 1
|
"xffNumTrustedHops": 1,
|
||||||
|
"internalAddressConfig": {
|
||||||
|
"cidrRanges": [
|
||||||
|
{
|
||||||
|
"addressPrefix": "127.0.0.1",
|
||||||
|
"prefixLen": 32
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addressPrefix": "::1",
|
||||||
|
"prefixLen": 128
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addressPrefix": "10.0.0.0",
|
||||||
|
"prefixLen": 8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addressPrefix": "192.168.0.0",
|
||||||
|
"prefixLen": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addressPrefix": "172.16.0.0",
|
||||||
|
"prefixLen": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addressPrefix": "fd00::",
|
||||||
|
"prefixLen": 8
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,35 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"statPrefix": "metrics"
|
"statPrefix": "metrics",
|
||||||
|
"internalAddressConfig": {
|
||||||
|
"cidrRanges": [
|
||||||
|
{
|
||||||
|
"addressPrefix": "127.0.0.1",
|
||||||
|
"prefixLen": 32
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addressPrefix": "::1",
|
||||||
|
"prefixLen": 128
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addressPrefix": "10.0.0.0",
|
||||||
|
"prefixLen": 8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addressPrefix": "192.168.0.0",
|
||||||
|
"prefixLen": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addressPrefix": "172.16.0.0",
|
||||||
|
"prefixLen": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addressPrefix": "fd00::",
|
||||||
|
"prefixLen": 8
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
@ -978,17 +978,6 @@ func TestOptions_ApplySettings(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestXXX(t *testing.T) {
|
|
||||||
dir, _ := os.MkdirTemp("", "asdf")
|
|
||||||
t.Log(dir)
|
|
||||||
for i := 1; i <= 100; i++ {
|
|
||||||
crt, _ := cryptutil.GenerateCertificate(nil, fmt.Sprintf("route%d.localhost.pomerium.io", i))
|
|
||||||
crtBytes, keyBytes, _ := cryptutil.EncodeCertificate(crt)
|
|
||||||
os.WriteFile(fmt.Sprintf("%s/%d.crt", dir, i), crtBytes, 0o644)
|
|
||||||
os.WriteFile(fmt.Sprintf("%s/%d.key", dir, i), keyBytes, 0o600)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOptions_GetSetResponseHeaders(t *testing.T) {
|
func TestOptions_GetSetResponseHeaders(t *testing.T) {
|
||||||
t.Run("lax", func(t *testing.T) {
|
t.Run("lax", func(t *testing.T) {
|
||||||
options := NewDefaultOptions()
|
options := NewDefaultOptions()
|
||||||
|
|
|
@ -28,6 +28,9 @@ import (
|
||||||
// Policy contains route specific configuration and access settings.
|
// Policy contains route specific configuration and access settings.
|
||||||
type Policy struct {
|
type Policy struct {
|
||||||
ID string `mapstructure:"-" yaml:"-" json:"-"`
|
ID string `mapstructure:"-" yaml:"-" json:"-"`
|
||||||
|
Name string `mapstructure:"-" yaml:"-" json:"-"`
|
||||||
|
Description string `mapstructure:"description" yaml:"description,omitempty" json:"description,omitempty"`
|
||||||
|
LogoURL string `mapstructure:"logo_url" yaml:"logo_url,omitempty" json:"logo_url,omitempty"`
|
||||||
|
|
||||||
From string `mapstructure:"from" yaml:"from"`
|
From string `mapstructure:"from" yaml:"from"`
|
||||||
To WeightedURLs `mapstructure:"to" yaml:"to"`
|
To WeightedURLs `mapstructure:"to" yaml:"to"`
|
||||||
|
@ -285,6 +288,7 @@ func NewPolicyFromProto(pb *configpb.Route) (*Policy, error) {
|
||||||
AllowSPDY: pb.GetAllowSpdy(),
|
AllowSPDY: pb.GetAllowSpdy(),
|
||||||
AllowWebsockets: pb.GetAllowWebsockets(),
|
AllowWebsockets: pb.GetAllowWebsockets(),
|
||||||
CORSAllowPreflight: pb.GetCorsAllowPreflight(),
|
CORSAllowPreflight: pb.GetCorsAllowPreflight(),
|
||||||
|
Description: pb.GetDescription(),
|
||||||
EnableGoogleCloudServerlessAuthentication: pb.GetEnableGoogleCloudServerlessAuthentication(),
|
EnableGoogleCloudServerlessAuthentication: pb.GetEnableGoogleCloudServerlessAuthentication(),
|
||||||
From: pb.GetFrom(),
|
From: pb.GetFrom(),
|
||||||
HostPathRegexRewritePattern: pb.GetHostPathRegexRewritePattern(),
|
HostPathRegexRewritePattern: pb.GetHostPathRegexRewritePattern(),
|
||||||
|
@ -298,6 +302,8 @@ func NewPolicyFromProto(pb *configpb.Route) (*Policy, error) {
|
||||||
JWTGroupsFilter: NewJWTGroupsFilter(pb.JwtGroupsFilter),
|
JWTGroupsFilter: NewJWTGroupsFilter(pb.JwtGroupsFilter),
|
||||||
KubernetesServiceAccountToken: pb.GetKubernetesServiceAccountToken(),
|
KubernetesServiceAccountToken: pb.GetKubernetesServiceAccountToken(),
|
||||||
KubernetesServiceAccountTokenFile: pb.GetKubernetesServiceAccountTokenFile(),
|
KubernetesServiceAccountTokenFile: pb.GetKubernetesServiceAccountTokenFile(),
|
||||||
|
LogoURL: pb.GetLogoUrl(),
|
||||||
|
Name: pb.GetName(),
|
||||||
PassIdentityHeaders: pb.PassIdentityHeaders,
|
PassIdentityHeaders: pb.PassIdentityHeaders,
|
||||||
Path: pb.GetPath(),
|
Path: pb.GetPath(),
|
||||||
Prefix: pb.GetPrefix(),
|
Prefix: pb.GetPrefix(),
|
||||||
|
@ -438,6 +444,7 @@ func (p *Policy) ToProto() (*configpb.Route, error) {
|
||||||
AllowSpdy: p.AllowSPDY,
|
AllowSpdy: p.AllowSPDY,
|
||||||
AllowWebsockets: p.AllowWebsockets,
|
AllowWebsockets: p.AllowWebsockets,
|
||||||
CorsAllowPreflight: p.CORSAllowPreflight,
|
CorsAllowPreflight: p.CORSAllowPreflight,
|
||||||
|
Description: p.Description,
|
||||||
EnableGoogleCloudServerlessAuthentication: p.EnableGoogleCloudServerlessAuthentication,
|
EnableGoogleCloudServerlessAuthentication: p.EnableGoogleCloudServerlessAuthentication,
|
||||||
EnvoyOpts: p.EnvoyOpts,
|
EnvoyOpts: p.EnvoyOpts,
|
||||||
From: p.From,
|
From: p.From,
|
||||||
|
@ -446,7 +453,8 @@ func (p *Policy) ToProto() (*configpb.Route, error) {
|
||||||
JwtGroupsFilter: p.JWTGroupsFilter.ToSlice(),
|
JwtGroupsFilter: p.JWTGroupsFilter.ToSlice(),
|
||||||
KubernetesServiceAccountToken: p.KubernetesServiceAccountToken,
|
KubernetesServiceAccountToken: p.KubernetesServiceAccountToken,
|
||||||
KubernetesServiceAccountTokenFile: p.KubernetesServiceAccountTokenFile,
|
KubernetesServiceAccountTokenFile: p.KubernetesServiceAccountTokenFile,
|
||||||
Name: fmt.Sprint(p.RouteID()),
|
LogoUrl: p.LogoURL,
|
||||||
|
Name: p.Name,
|
||||||
PassIdentityHeaders: p.PassIdentityHeaders,
|
PassIdentityHeaders: p.PassIdentityHeaders,
|
||||||
Path: p.Path,
|
Path: p.Path,
|
||||||
Policies: sps,
|
Policies: sps,
|
||||||
|
@ -476,6 +484,9 @@ func (p *Policy) ToProto() (*configpb.Route, error) {
|
||||||
TlsUpstreamAllowRenegotiation: p.TLSUpstreamAllowRenegotiation,
|
TlsUpstreamAllowRenegotiation: p.TLSUpstreamAllowRenegotiation,
|
||||||
TlsUpstreamServerName: p.TLSUpstreamServerName,
|
TlsUpstreamServerName: p.TLSUpstreamServerName,
|
||||||
}
|
}
|
||||||
|
if pb.Name == "" {
|
||||||
|
pb.Name = fmt.Sprint(p.RouteID())
|
||||||
|
}
|
||||||
if p.HostPathRegexRewritePattern != "" {
|
if p.HostPathRegexRewritePattern != "" {
|
||||||
pb.HostPathRegexRewritePattern = proto.String(p.HostPathRegexRewritePattern)
|
pb.HostPathRegexRewritePattern = proto.String(p.HostPathRegexRewritePattern)
|
||||||
}
|
}
|
||||||
|
@ -869,6 +880,26 @@ func (p *Policy) GetPassIdentityHeaders(options *Options) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetFrom gets the from URL.
|
||||||
|
func (p *Policy) GetFrom() string {
|
||||||
|
return p.From
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPath gets the path.
|
||||||
|
func (p *Policy) GetPath() string {
|
||||||
|
return p.Path
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPrefix gets the prefix.
|
||||||
|
func (p *Policy) GetPrefix() string {
|
||||||
|
return p.Prefix
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRegex gets the regex.
|
||||||
|
func (p *Policy) GetRegex() string {
|
||||||
|
return p.Regex
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
SortPolicies sorts policies to match the following SQL order:
|
SortPolicies sorts policies to match the following SQL order:
|
||||||
|
|
||||||
|
|
|
@ -218,6 +218,9 @@ func TestPolicy_FromToPb(t *testing.T) {
|
||||||
|
|
||||||
t.Run("normal", func(t *testing.T) {
|
t.Run("normal", func(t *testing.T) {
|
||||||
p := &Policy{
|
p := &Policy{
|
||||||
|
Name: "ROUTE_NAME",
|
||||||
|
Description: "DESCRIPTION",
|
||||||
|
LogoURL: "LOGO_URL",
|
||||||
From: "https://pomerium.io",
|
From: "https://pomerium.io",
|
||||||
To: mustParseWeightedURLs(t, "http://localhost"),
|
To: mustParseWeightedURLs(t, "http://localhost"),
|
||||||
AllowedUsers: []string{"foo@bar.com"},
|
AllowedUsers: []string{"foo@bar.com"},
|
||||||
|
@ -235,6 +238,9 @@ func TestPolicy_FromToPb(t *testing.T) {
|
||||||
|
|
||||||
policyFromPb, err := NewPolicyFromProto(pbPolicy)
|
policyFromPb, err := NewPolicyFromProto(pbPolicy)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, p.Name, policyFromPb.Name)
|
||||||
|
assert.Equal(t, p.Description, policyFromPb.Description)
|
||||||
|
assert.Equal(t, p.LogoURL, policyFromPb.LogoURL)
|
||||||
assert.Equal(t, p.From, policyFromPb.From)
|
assert.Equal(t, p.From, policyFromPb.From)
|
||||||
assert.Equal(t, p.To, policyFromPb.To)
|
assert.Equal(t, p.To, policyFromPb.To)
|
||||||
assert.Equal(t, p.AllowedUsers, policyFromPb.AllowedUsers)
|
assert.Equal(t, p.AllowedUsers, policyFromPb.AllowedUsers)
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -45,9 +45,11 @@ enum IssuerFormat {
|
||||||
IssuerURI = 1;
|
IssuerURI = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next ID: 67.
|
// Next ID: 69.
|
||||||
message Route {
|
message Route {
|
||||||
string name = 1;
|
string name = 1;
|
||||||
|
string description = 67;
|
||||||
|
string logo_url = 68;
|
||||||
|
|
||||||
string from = 2;
|
string from = 2;
|
||||||
repeated string to = 3;
|
repeated string to = 3;
|
||||||
|
|
|
@ -11,7 +11,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/cespare/xxhash/v2"
|
"github.com/cespare/xxhash/v2"
|
||||||
configpb "github.com/pomerium/pomerium/pkg/grpc/config"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func GenerateCertName(cert *x509.Certificate) *string {
|
func GenerateCertName(cert *x509.Certificate) *string {
|
||||||
|
@ -59,18 +58,26 @@ func pickDNSName(names []string) string {
|
||||||
return names[0]
|
return names[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenerateRouteNames(routes []*configpb.Route) []string {
|
type Route interface {
|
||||||
|
comparable
|
||||||
|
GetFrom() string
|
||||||
|
GetPrefix() string
|
||||||
|
GetPath() string
|
||||||
|
GetRegex() string
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenerateRouteNames[T Route](routes []T) []string {
|
||||||
out := make([]string, len(routes))
|
out := make([]string, len(routes))
|
||||||
prefixes := make([][]string, len(routes))
|
prefixes := make([][]string, len(routes))
|
||||||
indexes := map[*configpb.Route]int{}
|
indexes := map[T]int{}
|
||||||
trie := newDomainTrie()
|
trie := newDomainTrie[T]()
|
||||||
for i, route := range routes {
|
for i, route := range routes {
|
||||||
trie.Insert(route)
|
trie.Insert(route)
|
||||||
indexes[route] = i
|
indexes[route] = i
|
||||||
}
|
}
|
||||||
trie.Compact()
|
trie.Compact()
|
||||||
|
|
||||||
trie.Walk(func(parents []string, node *domainTreeNode) {
|
trie.Walk(func(parents []string, node *domainTreeNode[T]) {
|
||||||
for subdomain, child := range node.children {
|
for subdomain, child := range node.children {
|
||||||
for route, name := range differentiateRoutes(subdomain, child.routes) {
|
for route, name := range differentiateRoutes(subdomain, child.routes) {
|
||||||
idx := indexes[route]
|
idx := indexes[route]
|
||||||
|
@ -145,13 +152,13 @@ func trimCommonSubdomains(a, b string) (string, string) {
|
||||||
return strings.Join(aParts, "-"), strings.Join(bParts, "-")
|
return strings.Join(aParts, "-"), strings.Join(bParts, "-")
|
||||||
}
|
}
|
||||||
|
|
||||||
func differentiateRoutes(subdomain string, routes []*configpb.Route) iter.Seq2[*configpb.Route, string] {
|
func differentiateRoutes[T Route](subdomain string, routes []T) iter.Seq2[T, string] {
|
||||||
return func(yield func(*configpb.Route, string) bool) {
|
return func(yield func(T, string) bool) {
|
||||||
if len(routes) == 1 {
|
if len(routes) == 1 {
|
||||||
yield(routes[0], subdomain)
|
yield(routes[0], subdomain)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
names := map[string][]*configpb.Route{}
|
names := map[string][]T{}
|
||||||
replacer := strings.NewReplacer(
|
replacer := strings.NewReplacer(
|
||||||
" ", "_",
|
" ", "_",
|
||||||
"/", "-",
|
"/", "-",
|
||||||
|
@ -180,14 +187,14 @@ func differentiateRoutes(subdomain string, routes []*configpb.Route) iter.Seq2[*
|
||||||
// each route will have the same domain, but a unique prefix/path/regex.
|
// each route will have the same domain, but a unique prefix/path/regex.
|
||||||
var name string
|
var name string
|
||||||
switch {
|
switch {
|
||||||
case route.Prefix != "":
|
case route.GetPrefix() != "":
|
||||||
name = simplePathName(route.Prefix)
|
name = simplePathName(route.GetPrefix())
|
||||||
prefixCount++
|
prefixCount++
|
||||||
case route.Path != "":
|
case route.GetPath() != "":
|
||||||
name = simplePathName(route.Path)
|
name = simplePathName(route.GetPath())
|
||||||
pathCount++
|
pathCount++
|
||||||
case route.Regex != "":
|
case route.GetRegex() != "":
|
||||||
name = regexName(route.Regex)
|
name = regexName(route.GetRegex())
|
||||||
}
|
}
|
||||||
names[name] = append(names[name], route)
|
names[name] = append(names[name], route)
|
||||||
}
|
}
|
||||||
|
@ -229,9 +236,9 @@ func differentiateRoutes(subdomain string, routes []*configpb.Route) iter.Seq2[*
|
||||||
b.WriteRune('-')
|
b.WriteRune('-')
|
||||||
b.WriteString(name)
|
b.WriteString(name)
|
||||||
}
|
}
|
||||||
if route.Prefix != "" {
|
if route.GetPrefix() != "" {
|
||||||
b.WriteString(prefixSuffix)
|
b.WriteString(prefixSuffix)
|
||||||
} else if route.Path != "" {
|
} else if route.GetPath() != "" {
|
||||||
b.WriteString(pathSuffix)
|
b.WriteString(pathSuffix)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,58 +258,58 @@ func differentiateRoutes(subdomain string, routes []*configpb.Route) iter.Seq2[*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type domainTreeNode struct {
|
type domainTreeNode[T Route] struct {
|
||||||
parent *domainTreeNode
|
parent *domainTreeNode[T]
|
||||||
children map[string]*domainTreeNode
|
children map[string]*domainTreeNode[T]
|
||||||
routes []*configpb.Route
|
routes []T
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *domainTreeNode) insert(key string, route *configpb.Route) *domainTreeNode {
|
func (n *domainTreeNode[T]) insert(key string, route T) *domainTreeNode[T] {
|
||||||
if existing, ok := n.children[key]; ok {
|
if existing, ok := n.children[key]; ok {
|
||||||
if route != nil {
|
var def T
|
||||||
|
if route != def {
|
||||||
existing.routes = append(existing.routes, route)
|
existing.routes = append(existing.routes, route)
|
||||||
}
|
}
|
||||||
return existing
|
return existing
|
||||||
}
|
}
|
||||||
node := &domainTreeNode{
|
node := &domainTreeNode[T]{
|
||||||
parent: n,
|
parent: n,
|
||||||
children: map[string]*domainTreeNode{},
|
children: map[string]*domainTreeNode[T]{},
|
||||||
}
|
}
|
||||||
if route != nil {
|
var def T
|
||||||
|
if route != def {
|
||||||
node.routes = append(node.routes, route)
|
node.routes = append(node.routes, route)
|
||||||
}
|
}
|
||||||
n.children[key] = node
|
n.children[key] = node
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
type domainTrie struct {
|
type domainTrie[T Route] struct {
|
||||||
root *domainTreeNode
|
root *domainTreeNode[T]
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDomainTrie() *domainTrie {
|
func newDomainTrie[T Route]() *domainTrie[T] {
|
||||||
t := &domainTrie{
|
t := &domainTrie[T]{
|
||||||
root: &domainTreeNode{
|
root: &domainTreeNode[T]{
|
||||||
children: map[string]*domainTreeNode{},
|
children: map[string]*domainTreeNode[T]{},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
type walkFn = func(parents []string, node *domainTreeNode)
|
func (t *domainTrie[T]) Walk(fn func(parents []string, node *domainTreeNode[T])) {
|
||||||
|
|
||||||
func (t *domainTrie) Walk(fn walkFn) {
|
|
||||||
t.root.walk(nil, fn)
|
t.root.walk(nil, fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *domainTreeNode) walk(prefix []string, fn walkFn) {
|
func (n *domainTreeNode[T]) walk(prefix []string, fn func(parents []string, node *domainTreeNode[T])) {
|
||||||
for key, child := range n.children {
|
for key, child := range n.children {
|
||||||
fn(append(prefix, key), child)
|
fn(append(prefix, key), child)
|
||||||
child.walk(append(prefix, key), fn)
|
child.walk(append(prefix, key), fn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *domainTrie) Insert(route *configpb.Route) {
|
func (t *domainTrie[T]) Insert(route T) {
|
||||||
u, _ := url.Parse(route.From)
|
u, _ := url.Parse(route.GetFrom())
|
||||||
if u == nil {
|
if u == nil {
|
||||||
// ignore invalid urls, they will be assigned generic fallback names
|
// ignore invalid urls, they will be assigned generic fallback names
|
||||||
return
|
return
|
||||||
|
@ -311,16 +318,17 @@ func (t *domainTrie) Insert(route *configpb.Route) {
|
||||||
slices.Reverse(parts)
|
slices.Reverse(parts)
|
||||||
cur := t.root
|
cur := t.root
|
||||||
for _, part := range parts[:len(parts)-1] {
|
for _, part := range parts[:len(parts)-1] {
|
||||||
cur = cur.insert(part, nil)
|
var def T
|
||||||
|
cur = cur.insert(part, def)
|
||||||
}
|
}
|
||||||
cur.insert(parts[len(parts)-1], route)
|
cur.insert(parts[len(parts)-1], route)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *domainTrie) Compact() {
|
func (t *domainTrie[T]) Compact() {
|
||||||
t.root.compact()
|
t.root.compact()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *domainTreeNode) compact() {
|
func (n *domainTreeNode[T]) compact() {
|
||||||
for _, child := range n.children {
|
for _, child := range n.children {
|
||||||
child.compact()
|
child.compact()
|
||||||
}
|
}
|
||||||
|
@ -328,7 +336,7 @@ func (n *domainTreeNode) compact() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var firstKey string
|
var firstKey string
|
||||||
var firstChild *domainTreeNode
|
var firstChild *domainTreeNode[T]
|
||||||
for key, child := range n.children {
|
for key, child := range n.children {
|
||||||
firstKey, firstChild = key, child
|
firstKey, firstChild = key, child
|
||||||
break
|
break
|
||||||
|
@ -340,7 +348,7 @@ func (n *domainTreeNode) compact() {
|
||||||
if child == n {
|
if child == n {
|
||||||
delete(n.parent.children, key)
|
delete(n.parent.children, key)
|
||||||
n.parent.children[fmt.Sprintf("%s.%s", key, firstKey)] = firstChild
|
n.parent.children[fmt.Sprintf("%s.%s", key, firstKey)] = firstChild
|
||||||
*n = domainTreeNode{}
|
*n = domainTreeNode[T]{}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,11 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/pomerium/pomerium/config"
|
||||||
configpb "github.com/pomerium/pomerium/pkg/grpc/config"
|
configpb "github.com/pomerium/pomerium/pkg/grpc/config"
|
||||||
"github.com/pomerium/pomerium/pkg/zero/importutil"
|
"github.com/pomerium/pomerium/pkg/zero/importutil"
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGenerateCertName(t *testing.T) {
|
func TestGenerateCertName(t *testing.T) {
|
||||||
|
@ -389,6 +391,11 @@ func TestGenerateRouteNames(t *testing.T) {
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
assert.Equal(t, tc.expected, importutil.GenerateRouteNames(tc.input))
|
assert.Equal(t, tc.expected, importutil.GenerateRouteNames(tc.input))
|
||||||
|
policies := make([]*config.Policy, len(tc.input))
|
||||||
|
for i := range tc.input {
|
||||||
|
policies[i], _ = config.NewPolicyFromProto(tc.input[i])
|
||||||
|
}
|
||||||
|
assert.Equal(t, tc.expected, importutil.GenerateRouteNames(policies))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue