Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(kuma-cp) initial connection policy support for Gateway #2933

Merged
merged 1 commit into from
Oct 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions pkg/core/policy/match.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package policy

import (
mesh_proto "github.com/kumahq/kuma/api/mesh/v1alpha1"
)

// MatchSelector succeeds if any of the given selectors matches the tags. It
// additionally returns the rank of the selector that matched the tag.
func MatchSelector(tags map[string]string, selectors []*mesh_proto.Selector) (mesh_proto.TagSelectorRank, bool) {
for _, selector := range selectors {
sourceSelector := mesh_proto.TagSelector(selector.GetMatch())
if sourceSelector.Matches(tags) {
return sourceSelector.Rank(), true
}
}

return mesh_proto.TagSelectorRank{}, false
}
83 changes: 83 additions & 0 deletions pkg/plugins/runtime/gateway/connection_policy_generator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package gateway

import (
"sort"

mesh_proto "github.com/kumahq/kuma/api/mesh/v1alpha1"
"github.com/kumahq/kuma/pkg/core/policy"
"github.com/kumahq/kuma/pkg/core/resources/model"
core_xds "github.com/kumahq/kuma/pkg/core/xds"
"github.com/kumahq/kuma/pkg/plugins/runtime/gateway/match"
xds_context "github.com/kumahq/kuma/pkg/xds/context"
"github.com/kumahq/kuma/pkg/xds/envoy"
)

// ConnectionPolicyGenerator matches connection policies for each route table
// entry that forwards traffic.
type ConnectionPolicyGenerator struct {
}

func (*ConnectionPolicyGenerator) SupportsProtocol(p mesh_proto.Gateway_Listener_Protocol) bool {
return true
}

func (g *ConnectionPolicyGenerator) GenerateHost(ctx xds_context.Context, info *GatewayResourceInfo) (*core_xds.ResourceSet, error) {
for _, e := range info.RouteTable.Entries {
for i, destination := range e.Action.Forward {
e.Action.Forward[i].Policies = mapPoliciesForDestination(destination.Destination, info)
}
if e.Mirror != nil {
e.Mirror.Forward.Policies = mapPoliciesForDestination(e.Mirror.Forward.Destination, info)
}
}

return nil, nil
}

func mapPoliciesForDestination(destination envoy.Tags, info *GatewayResourceInfo) map[model.ResourceType]model.Resource {
policies := map[model.ResourceType]model.Resource{}

for _, policyType := range ConnectionPolicyTypes {
if policy := matchConnectionPolicy(info.Host.Policies[policyType], destination); policy != nil {
policies[policyType] = policy
}
}

return policies
}

func matchConnectionPolicy(candidates []match.RankedPolicy, destination envoy.Tags) model.Resource {
var matches []match.RankedPolicy

for _, c := range candidates {
if rank, ok := policy.MatchSelector(destination, c.Policy.Destinations()); ok {
// Track this match with the combined source+destination rank.
matches = append(matches, match.RankedPolicy{
Rank: rank.CombinedWith(c.Rank),
Policy: c.Policy,
})
}
}

if len(matches) == 0 {
return nil
}

// Sort more specific (higher ranked) policies first.
sort.Slice(matches, func(i, j int) bool {
n := matches[i].Rank.CompareTo(matches[j].Rank)
switch {
case n < 0:
return false
case n > 0:
return true
default /* i == 0 */ :
// If the rank is the same, the most recent
// policy sorts to the front (i.e. takes priority).
return matches[i].Policy.GetMeta().GetCreationTime().After(
matches[j].Policy.GetMeta().GetCreationTime())
}
})

return matches[0].Policy
}
2 changes: 1 addition & 1 deletion pkg/plugins/runtime/gateway/gateway_route_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func (g *GatewayRouteGenerator) GenerateHost(ctx xds_context.Context, info *Gate
}
}

// The kubernetes Ingress and Gateway APIs define prefix matching
// The Kubernetes Ingress and Gateway APIs define prefix matching
// to match in terms of path components, so we follow suit here.
// Envoy path prefix matching is byte-wise, so we need to do some
// transformations. Unless there is already an exact match for the
Expand Down
250 changes: 244 additions & 6 deletions pkg/plugins/runtime/gateway/gateway_route_generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,9 @@ var _ = Describe("Gateway Gateway Route", func() {

dataplanes = &DataplaneGenerator{Manager: rt.ResourceManager()}

dataplanes.Generate("echo-service")
dataplanes.Generate("echo-mirror")
dataplanes.Generate("exact-header-match")
dataplanes.Generate("regex-header-match")

// Add dataplane resources for all the services used in the test suite.
for _, service := range []string{
"api-service",
"echo-exact",
"echo-mirror",
"echo-prefix",
Expand Down Expand Up @@ -566,6 +562,248 @@ conf:
kuma.io/service: echo-service
`,
),
)

Entry("match timeout policy",
"15-gateway-route.yaml", `
type: GatewayRoute
mesh: default
name: echo-service
selectors:
- match:
kuma.io/service: gateway-default
conf:
http:
rules:
- matches:
- path:
match: PREFIX
value: /
filters:
- mirror:
percentage: 1
backend:
destination:
kuma.io/service: echo-mirror
backends:
- destination:
kuma.io/service: echo-service
- matches:
- path:
match: PREFIX
value: /api
backends:
- destination:
kuma.io/service: api-service
`, `
type: Timeout
mesh: default
name: echo-service
sources:
- match:
kuma.io/service: gateway-default
destinations:
- match:
kuma.io/service: echo-service
conf:
connect_timeout: 10s
http:
request_timeout: 10s
idle_timeout: 10s
`, `
type: Timeout
mesh: default
name: api-service
sources:
- match:
kuma.io/service: gateway-default
destinations:
- match:
kuma.io/service: api-service
conf:
connect_timeout: 20s
http:
request_timeout: 20s
idle_timeout: 20s
`, `
type: Timeout
mesh: default
name: echo-mirror
sources:
- match:
kuma.io/service: gateway-default
destinations:
- match:
kuma.io/service: echo-mirror
conf:
connect_timeout: 300s
http:
request_timeout: 30s
idle_timeout: 30s
`,
),

Entry("match circuit breaker policy",
"16-gateway-route.yaml", `
type: GatewayRoute
mesh: default
name: echo-service
selectors:
- match:
kuma.io/service: gateway-default
conf:
http:
rules:
- matches:
- path:
match: PREFIX
value: /
filters:
- mirror:
percentage: 1
backend:
destination:
kuma.io/service: echo-mirror
backends:
- destination:
kuma.io/service: echo-service
- matches:
- path:
match: PREFIX
value: /api
backends:
- destination:
kuma.io/service: api-service
`, `
type: CircuitBreaker
mesh: default
name: echo-service
sources:
- match:
kuma.io/service: gateway-default
destinations:
- match:
kuma.io/service: echo-service
conf:
baseEjectionTime: 10s
thresholds:
maxRetries: 10
detectors:
localErrors:
consecutive: 10
`, `
type: CircuitBreaker
mesh: default
name: api-service
sources:
- match:
kuma.io/service: gateway-default
destinations:
- match:
kuma.io/service: api-service
conf:
baseEjectionTime: 20s
thresholds:
maxRetries: 20
detectors:
localErrors:
consecutive: 20
`, `
type: CircuitBreaker
mesh: default
name: echo-mirror
sources:
- match:
kuma.io/service: gateway-default
destinations:
- match:
kuma.io/service: echo-mirror
conf:
baseEjectionTime: 30s
thresholds:
maxRetries: 20
detectors:
localErrors:
consecutive: 30
`,
),

Entry("match health check policy",
"17-gateway-route.yaml", `
type: GatewayRoute
mesh: default
name: echo-service
selectors:
- match:
kuma.io/service: gateway-default
conf:
http:
rules:
- matches:
- path:
match: PREFIX
value: /
filters:
- mirror:
percentage: 1
backend:
destination:
kuma.io/service: echo-mirror
backends:
- destination:
kuma.io/service: echo-service
- matches:
- path:
match: PREFIX
value: /api
backends:
- destination:
kuma.io/service: api-service
`, `
type: HealthCheck
mesh: default
name: echo-service
sources:
- match:
kuma.io/service: gateway-default
destinations:
- match:
kuma.io/service: echo-service
conf:
interval: 10s
timeout: 10s
healthyThreshold: 1
unhealthyThreshold: 1
`, `
type: HealthCheck
mesh: default
name: api-service
sources:
- match:
kuma.io/service: gateway-default
destinations:
- match:
kuma.io/service: api-service
conf:
interval: 20s
timeout: 20s
healthyThreshold: 2
unhealthyThreshold: 2
`, `
type: HealthCheck
mesh: default
name: echo-mirror
sources:
- match:
kuma.io/service: gateway-default
destinations:
- match:
kuma.io/service: echo-mirror
conf:
interval: 30s
timeout: 30s
healthyThreshold: 3
unhealthyThreshold: 3
`,
),
)
})
Loading