Skip to content

Commit

Permalink
feat(kuma-cp): resolve labels for backendref (#11360)
Browse files Browse the repository at this point in the history
Signed-off-by: Jakub Dyszkiewicz <jakub.dyszkiewicz@gmail.com>
  • Loading branch information
jakubdyszkiewicz authored Sep 11, 2024
1 parent 0995b09 commit d0b5091
Show file tree
Hide file tree
Showing 28 changed files with 933 additions and 234 deletions.
10 changes: 9 additions & 1 deletion api/common/v1alpha1/ref.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,17 @@ func (in BackendRef) Hash() BackendRefHash {
for _, k := range keys {
orderedTags = append(orderedTags, fmt.Sprintf("%s=%s", k, in.Tags[k]))
}

keys = maps.Keys(in.Labels)
sort.Strings(keys)
orderedLabels := make([]string, 0, len(in.Labels))
for _, k := range keys {
orderedLabels = append(orderedLabels, fmt.Sprintf("%s=%s", k, in.Labels[k]))
}

name := in.Name
if in.Port != nil {
name = fmt.Sprintf("%s_svc_%d", in.Name, *in.Port)
}
return BackendRefHash(fmt.Sprintf("%s/%s/%s/%s", in.Kind, name, strings.Join(orderedTags, "/"), in.Mesh))
return BackendRefHash(fmt.Sprintf("%s/%s/%s/%s/%s", in.Kind, name, strings.Join(orderedTags, "/"), strings.Join(orderedLabels, "/"), in.Mesh))
}
403 changes: 213 additions & 190 deletions api/mesh/v1alpha1/dataplane.pb.go

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions api/mesh/v1alpha1/dataplane.proto
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,10 @@ message Dataplane {
string name = 2;
// Port of the targeted object. Required when kind is MeshService.
uint32 port = 3;
// Labels to select a single object.
// If no object is selected then outbound is not created.
// If multiple objects are selected then the oldest one is used.
map<string, string> labels = 4;
}
}

Expand Down
7 changes: 7 additions & 0 deletions docs/generated/raw/protos/Dataplane.json
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,13 @@
"port": {
"type": "integer",
"description": "Port of the targeted object. Required when kind is MeshService."
},
"labels": {
"additionalProperties": {
"type": "string"
},
"type": "object",
"description": "Labels to select a single object. If no object is selected then outbound is not created. If multiple objects are selected then the oldest one is used."
}
},
"additionalProperties": true,
Expand Down
7 changes: 7 additions & 0 deletions docs/generated/raw/protos/DataplaneOverview.json
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,13 @@
"port": {
"type": "integer",
"description": "Port of the targeted object. Required when kind is MeshService."
},
"labels": {
"additionalProperties": {
"type": "string"
},
"type": "object",
"description": "Labels to select a single object. If no object is selected then outbound is not created. If multiple objects are selected then the oldest one is used."
}
},
"additionalProperties": true,
Expand Down
22 changes: 15 additions & 7 deletions pkg/core/resources/apis/mesh/dataplane_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,25 +233,33 @@ func (d *DataplaneResource) Hash() []byte {
return hasher.Sum(nil)
}

func (d *DataplaneResource) AsOutbounds() xds_types.Outbounds {
func (d *DataplaneResource) AsOutbounds(resolver core_model.LabelResourceIdentifierResolver) xds_types.Outbounds {
var outbounds xds_types.Outbounds
for _, o := range d.Spec.Networking.Outbound {
if o.BackendRef != nil {
outbounds = append(outbounds, &xds_types.Outbound{
outbound := &xds_types.Outbound{
Address: o.Address,
Port: o.Port,
Resource: &core_model.TypedResourceIdentifier{
ResourceIdentifier: core_model.TargetRefToResourceIdentifier(
d.GetMeta(),
common_api.TargetRef{
Kind: common_api.MeshService,
Name: o.BackendRef.Name,
SectionName: fmt.Sprintf("%d", o.BackendRef.Port),
Kind: common_api.TargetRefKind(o.BackendRef.Kind),
Name: o.BackendRef.Name,
// todo(lobkovilya): add namespace to Dataplane_Networking_Outbound_BackendRef
}),
ResourceType: core_model.ResourceType(common_api.MeshService),
ResourceType: core_model.ResourceType(o.BackendRef.Kind),
},
})
}
if len(o.BackendRef.Labels) > 0 {
resIdentifier := resolver(core_model.ResourceType(o.BackendRef.Kind), o.BackendRef.Labels)
if resIdentifier == nil {
continue
}
outbound.Resource.ResourceIdentifier = *resIdentifier
}
outbound.Resource.SectionName = fmt.Sprintf("%d", o.BackendRef.Port)
outbounds = append(outbounds, outbound)
} else {
outbounds = append(outbounds, &xds_types.Outbound{LegacyOutbound: o})
}
Expand Down
16 changes: 13 additions & 3 deletions pkg/core/resources/model/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -718,27 +718,37 @@ func TargetRefToResourceIdentifier(meta ResourceMeta, tr common_api.TargetRef) R
}
}

func ResolveBackendRef(meta ResourceMeta, br common_api.BackendRef) ResolvedBackendRef {
type LabelResourceIdentifierResolver func(ResourceType, map[string]string) *ResourceIdentifier

func ResolveBackendRef(meta ResourceMeta, br common_api.BackendRef, resolver LabelResourceIdentifierResolver) *ResolvedBackendRef {
resolved := ResolvedBackendRef{LegacyBackendRef: &br}

switch {
case br.Kind == common_api.MeshService && br.ReferencesRealObject():
case br.Kind == common_api.MeshExternalService:
case br.Kind == common_api.MeshMultiZoneService:
default:
return resolved
return &resolved
}

resolved.Resource = &TypedResourceIdentifier{
ResourceIdentifier: TargetRefToResourceIdentifier(meta, br.TargetRef),
ResourceType: ResourceType(br.Kind),
}

if len(br.Labels) > 0 {
ri := resolver(ResourceType(br.Kind), br.Labels)
if ri == nil {
return nil
}
resolved.Resource.ResourceIdentifier = *ri
}

if br.Port != nil {
resolved.Resource.SectionName = fmt.Sprintf("%d", *br.Port)
}

return resolved
return &resolved
}

func (r ResourceIdentifier) String() string {
Expand Down
3 changes: 3 additions & 0 deletions pkg/plugins/policies/core/xds/meshroute/gateway/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
mesh_proto "github.com/kumahq/kuma/api/mesh/v1alpha1"
"github.com/kumahq/kuma/pkg/core/permissions"
core_mesh "github.com/kumahq/kuma/pkg/core/resources/apis/mesh"
"github.com/kumahq/kuma/pkg/core/resources/model"
core_xds "github.com/kumahq/kuma/pkg/core/xds"
"github.com/kumahq/kuma/pkg/plugins/policies/core/rules"
plugin_gateway "github.com/kumahq/kuma/pkg/plugins/runtime/gateway"
Expand All @@ -35,6 +36,7 @@ type MapGatewayRulesToHosts func(
port uint32,
protocol mesh_proto.MeshGateway_Listener_Protocol,
sublisteners []Sublistener,
resolver model.LabelResourceIdentifierResolver,
) []plugin_gateway.GatewayListenerHostname

func CollectListenerInfos(
Expand Down Expand Up @@ -103,6 +105,7 @@ func CollectListenerInfos(
listener.listener.GetPort(),
listener.listener.GetProtocol(),
listener.sublisteners,
meshCtx.ResolveResourceIdentifier,
)

infos[port] = plugin_gateway.GatewayListenerInfo{
Expand Down
15 changes: 11 additions & 4 deletions pkg/plugins/policies/meshhttproute/api/v1alpha1/compare.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,11 @@ type Route struct {
// https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.HTTPRouteRule
// We treat RegularExpression matches, which are implementation-specific, the
// same as prefix matches, the longer length match has priority.
func SortRules(rules []Rule, backendRefToOrigin map[string]core_model.ResourceMeta) []Route {
func SortRules(
rules []Rule,
backendRefToOrigin map[string]core_model.ResourceMeta,
labelResolver core_model.LabelResourceIdentifierResolver,
) []Route {
type keyed struct {
sortKey Match
rule Rule
Expand All @@ -122,15 +126,18 @@ func SortRules(rules []Rule, backendRefToOrigin map[string]core_model.ResourceMe
var out []Route
for _, key := range keys {
var backendRefs []core_model.ResolvedBackendRef
hashMatches := HashMatches(key.rule.Matches)
for _, br := range pointer.Deref(key.rule.Default.BackendRefs) {
if origin, ok := backendRefToOrigin[HashMatches(key.rule.Matches)]; ok {
backendRefs = append(backendRefs, core_model.ResolveBackendRef(origin, br))
if origin, ok := backendRefToOrigin[hashMatches]; ok {
if resolved := core_model.ResolveBackendRef(origin, br, labelResolver); resolved != nil {
backendRefs = append(backendRefs, *resolved)
}
} else {
backendRefs = append(backendRefs, core_model.ResolvedBackendRef{LegacyBackendRef: &br})
}
}
out = append(out, Route{
Hash: HashMatches(key.rule.Matches),
Hash: hashMatches,
Match: key.sortKey,
BackendRefs: backendRefs,
Filters: pointer.Deref(key.rule.Default.Filters),
Expand Down
22 changes: 11 additions & 11 deletions pkg/plugins/policies/meshhttproute/api/v1alpha1/compare_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,10 @@ var _ = Describe("SortRules", func() {
}},
}
It("handles base cases", func() {
Expect(api.SortRules(makeSingleMatchRules([]api.Match{}), nil)).To(Equal(makeRoutes([]api.Match{})))
Expect(api.SortRules(makeSingleMatchRules([]api.Match{}), nil, nil)).To(Equal(makeRoutes([]api.Match{})))
Expect(api.SortRules(makeSingleMatchRules([]api.Match{
exactMatch,
}), nil)).To(Equal(makeRoutes([]api.Match{
}), nil, nil)).To(Equal(makeRoutes([]api.Match{
exactMatch,
})))
})
Expand All @@ -131,7 +131,7 @@ var _ = Describe("SortRules", func() {
longerPrefixMatch,
regexMatch,
exactMatch,
}), nil)).To(Equal(makeRoutes([]api.Match{
}), nil, nil)).To(Equal(makeRoutes([]api.Match{
exactMatch,
longerPrefixMatch,
prefixMatch,
Expand All @@ -142,21 +142,21 @@ var _ = Describe("SortRules", func() {
Expect(api.SortRules(makeSingleMatchRules([]api.Match{
methodMatch,
exactMatch,
}), nil)).To(Equal(makeRoutes([]api.Match{
}), nil, nil)).To(Equal(makeRoutes([]api.Match{
exactMatch,
methodMatch,
})))
Expect(api.SortRules(makeSingleMatchRules([]api.Match{
singleHeaderMatch,
exactMatch,
}), nil)).To(Equal(makeRoutes([]api.Match{
}), nil, nil)).To(Equal(makeRoutes([]api.Match{
exactMatch,
singleHeaderMatch,
})))
Expect(api.SortRules(makeSingleMatchRules([]api.Match{
singleHeaderMatch,
prefixMatch,
}), nil)).To(Equal(makeRoutes([]api.Match{
}), nil, nil)).To(Equal(makeRoutes([]api.Match{
prefixMatch,
singleHeaderMatch,
})))
Expand All @@ -165,14 +165,14 @@ var _ = Describe("SortRules", func() {
Expect(api.SortRules(makeSingleMatchRules([]api.Match{
exactMatch,
exactAndMethodMatch,
}), nil)).To(Equal(makeRoutes([]api.Match{
}), nil, nil)).To(Equal(makeRoutes([]api.Match{
exactAndMethodMatch,
exactMatch,
})))
Expect(api.SortRules(makeSingleMatchRules([]api.Match{
exactSingleHeaderMatch,
exactDoubleHeaderMatch,
}), nil)).To(Equal(makeRoutes([]api.Match{
}), nil, nil)).To(Equal(makeRoutes([]api.Match{
exactDoubleHeaderMatch,
exactSingleHeaderMatch,
})))
Expand All @@ -181,14 +181,14 @@ var _ = Describe("SortRules", func() {
Expect(api.SortRules(makeSingleMatchRules([]api.Match{
exactMatch,
otherExactMatch,
}), nil)).To(Equal(makeRoutes([]api.Match{
}), nil, nil)).To(Equal(makeRoutes([]api.Match{
exactMatch,
otherExactMatch,
})))
Expect(api.SortRules(makeSingleMatchRules([]api.Match{
otherExactMatch,
exactMatch,
}), nil)).To(Equal(makeRoutes([]api.Match{
}), nil, nil)).To(Equal(makeRoutes([]api.Match{
otherExactMatch,
exactMatch,
})))
Expand All @@ -199,7 +199,7 @@ var _ = Describe("SortRules", func() {
Expect(api.SortRules(makeMultiMatchRules([][]api.Match{
prefixMatchOnly,
singleOrExact,
}), nil)).To(Equal([]api.Route{{
}), nil, nil)).To(Equal([]api.Route{{
Match: exactMatch,
Hash: api.HashMatches(singleOrExact),
}, {
Expand Down
2 changes: 2 additions & 0 deletions pkg/plugins/policies/meshhttproute/api/v1alpha1/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ func validateToRef(topTargetRef, targetRef common_api.TargetRef) validators.Vali
SupportedKinds: []common_api.TargetRefKind{
common_api.MeshService,
common_api.MeshExternalService,
common_api.MeshMultiZoneService,
},
})
}
Expand Down Expand Up @@ -374,6 +375,7 @@ func validateBackendRefs(
common_api.MeshService,
common_api.MeshServiceSubset,
common_api.MeshExternalService,
common_api.MeshMultiZoneService,
},
AllowedInvalidNames: []string{metadata.UnresolvedBackendServiceTag},
}),
Expand Down
33 changes: 33 additions & 0 deletions pkg/plugins/policies/meshhttproute/api/v1alpha1/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,39 @@ to:
backendRefs:
- kind: MeshService
name: backend
`),
Entry("MeshService and MeshMultiZoneService", `
type: MeshHTTPRoute
mesh: mesh-1
name: route-1
targetRef:
kind: Mesh
to:
- targetRef:
kind: MeshService
labels:
kuma.io/display-name: backend
rules:
- matches:
- path:
value: /v1
type: PathPrefix
default:
backendRefs:
- kind: MeshService
labels:
kuma.io/display-name: backend
port: 8080
- matches:
- path:
value: /v2
type: PathPrefix
default:
backendRefs:
- kind: MeshMultiZoneService
labels:
kuma.io/display-name: backend
port: 8080
`),
)
})
Loading

0 comments on commit d0b5091

Please sign in to comment.