Skip to content

Commit

Permalink
feat(reachableservices): implement reachable services for Mesh*Servic…
Browse files Browse the repository at this point in the history
…e and auto-rechable services for MeshExternalService (#10869)

Signed-off-by: Lukasz Dziedziak <lukidzi@gmail.com>
  • Loading branch information
lukidzi committed Aug 14, 2024
1 parent 97cb57b commit 09b7fb3
Show file tree
Hide file tree
Showing 33 changed files with 2,088 additions and 259 deletions.
414 changes: 317 additions & 97 deletions api/mesh/v1alpha1/dataplane.pb.go

Large diffs are not rendered by default.

24 changes: 24 additions & 0 deletions api/mesh/v1alpha1/dataplane.proto
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,30 @@ message Dataplane {

// The IP family mode to enable for. Can be "IPv4" or "DualStack".
IpFamilyMode ip_family_mode = 6;
message ReachableBackendRef {
// Type of the backend: MeshService or MeshExternalService
// +required
string kind = 1;
// Name of the backend.
// +optional
string name = 2;
// Namespace of the backend. Might be empty
// +optional
string namespace = 3;
// Port of the backend.
// +optional
google.protobuf.UInt32Value port = 4;
// Labels used to select backends
// +optional
map<string, string> labels = 5;
}

message ReachableBackends { repeated ReachableBackendRef refs = 1; }
// Reachable backend via transparent proxy when running with
// MeshExternalService, MeshService and MeshMultiZoneService. Setting an
// explicit list of refs can dramatically improve the performance of the
// mesh. If not specified, all services in the mesh are reachable.
ReachableBackends reachable_backends = 7;
}

// Gateway describes a configuration of the gateway of the data plane proxy.
Expand Down
49 changes: 49 additions & 0 deletions docs/generated/raw/protos/Dataplane.json
Original file line number Diff line number Diff line change
Expand Up @@ -309,13 +309,62 @@
}
],
"title": "Ip Family Mode"
},
"reachable_backends": {
"$ref": "#/definitions/kuma.mesh.v1alpha1.Dataplane.Networking.TransparentProxying.ReachableBackends",
"additionalProperties": true,
"description": "Reachable backend via transparent proxy when running with MeshExternalService, MeshService and MeshMultiZoneService. Setting an explicit list of refs can dramatically improve the performance of the mesh. If not specified, all services in the mesh are reachable."
}
},
"additionalProperties": true,
"type": "object",
"title": "Transparent Proxying",
"description": "TransparentProxying describes configuration for transparent proxying."
},
"kuma.mesh.v1alpha1.Dataplane.Networking.TransparentProxying.ReachableBackendRef": {
"properties": {
"kind": {
"type": "string",
"description": "Type of the backend: MeshService or MeshExternalService +required"
},
"name": {
"type": "string",
"description": "Name of the backend. +optional"
},
"namespace": {
"type": "string",
"description": "Namespace of the backend. Might be empty +optional"
},
"port": {
"additionalProperties": true,
"type": "integer",
"description": "Port of the backend. +optional"
},
"labels": {
"additionalProperties": {
"type": "string"
},
"type": "object",
"description": "Labels used to select backends +optional"
}
},
"additionalProperties": true,
"type": "object",
"title": "Reachable Backend Ref"
},
"kuma.mesh.v1alpha1.Dataplane.Networking.TransparentProxying.ReachableBackends": {
"properties": {
"refs": {
"items": {
"$ref": "#/definitions/kuma.mesh.v1alpha1.Dataplane.Networking.TransparentProxying.ReachableBackendRef"
},
"type": "array"
}
},
"additionalProperties": true,
"type": "object",
"title": "Reachable Backends"
},
"kuma.mesh.v1alpha1.Dataplane.Probes": {
"properties": {
"port": {
Expand Down
49 changes: 49 additions & 0 deletions docs/generated/raw/protos/DataplaneOverview.json
Original file line number Diff line number Diff line change
Expand Up @@ -325,13 +325,62 @@
}
],
"title": "Ip Family Mode"
},
"reachable_backends": {
"$ref": "#/definitions/kuma.mesh.v1alpha1.Dataplane.Networking.TransparentProxying.ReachableBackends",
"additionalProperties": true,
"description": "Reachable backend via transparent proxy when running with MeshExternalService, MeshService and MeshMultiZoneService. Setting an explicit list of refs can dramatically improve the performance of the mesh. If not specified, all services in the mesh are reachable."
}
},
"additionalProperties": true,
"type": "object",
"title": "Transparent Proxying",
"description": "TransparentProxying describes configuration for transparent proxying."
},
"kuma.mesh.v1alpha1.Dataplane.Networking.TransparentProxying.ReachableBackendRef": {
"properties": {
"kind": {
"type": "string",
"description": "Type of the backend: MeshService or MeshExternalService +required"
},
"name": {
"type": "string",
"description": "Name of the backend. +optional"
},
"namespace": {
"type": "string",
"description": "Namespace of the backend. Might be empty +optional"
},
"port": {
"additionalProperties": true,
"type": "integer",
"description": "Port of the backend. +optional"
},
"labels": {
"additionalProperties": {
"type": "string"
},
"type": "object",
"description": "Labels used to select backends +optional"
}
},
"additionalProperties": true,
"type": "object",
"title": "Reachable Backend Ref"
},
"kuma.mesh.v1alpha1.Dataplane.Networking.TransparentProxying.ReachableBackends": {
"properties": {
"refs": {
"items": {
"$ref": "#/definitions/kuma.mesh.v1alpha1.Dataplane.Networking.TransparentProxying.ReachableBackendRef"
},
"type": "array"
}
},
"additionalProperties": true,
"type": "object",
"title": "Reachable Backends"
},
"kuma.mesh.v1alpha1.Dataplane.Probes": {
"properties": {
"port": {
Expand Down
15 changes: 8 additions & 7 deletions docs/madr/decisions/056-reachable-svc-mesh-service.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ Chosen option: Support reachable and autoreachable services for `MeshService` an
In the case of Kubernetes, we can introduce a new annotation that has a more structured model and better flexibility.

```yaml
kuma.io/reachable-backend-refs: |
kuma.io/reachable-backends: |
refs:
- kind: MeshService
name: demo-app
Expand Down Expand Up @@ -123,12 +123,13 @@ message TransparentProxying {
map<string, string> labels = 5;
}
// List of reachable backend refs via transparent proxy when running with
// MeshExternalService and MeshService. Setting an explicit list
// can dramatically improve the performance of the mesh. If not specified,
// all services in the mesh are reachable.
repeated ReachableBackendRef reachable_backends_ref = 7;
}
message ReachableBackends { repeated ReachableBackendRef refs = 1; }
// Reachable backend via transparent proxy when running with
// MeshExternalService, MeshService and MeshMultiZoneService. Setting an
// explicit list of refs can dramatically improve the performance of the
// mesh. If not specified, all services in the mesh are reachable.
ReachableBackends reachable_backends = 7;
}
```

Most of the fields are optional and may not be used simultaneously. We need to support the following cases:
Expand Down
38 changes: 33 additions & 5 deletions pkg/core/resources/apis/mesh/dataplane_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ import (

"github.com/asaskevich/govalidator"

common_api "github.com/kumahq/kuma/api/common/v1alpha1"
mesh_proto "github.com/kumahq/kuma/api/mesh/v1alpha1"
"github.com/kumahq/kuma/pkg/core/validators"
"github.com/kumahq/kuma/pkg/util/maps"
)

const meshExternalServiceKind = "MeshExternalService"

var allowedKinds = map[string]struct{}{
"MeshService": {},
meshExternalServiceKind: {},
string(common_api.MeshService): {},
string(common_api.MeshExternalService): {},
string(common_api.MeshMultiZoneService): {},
}

func (d *DataplaneResource) Validate() error {
Expand Down Expand Up @@ -102,6 +102,7 @@ func validateNetworking(networking *mesh_proto.Dataplane_Networking) validators.
result := validateOutbound(outbound)
err.AddErrorAt(path.Field("outbound").Index(i), result)
}
err.AddErrorAt(path.Field("transparentProxing"), validateTransparentProxying(networking.GetTransparentProxying()))
return err
}

Expand Down Expand Up @@ -236,7 +237,7 @@ func validateOutbound(outbound *mesh_proto.Dataplane_Networking_Outbound) valida
result.AddViolation("backendRef.name", "cannot be empty")
}
// for MeshExternalService the port does not matter because it's taken from endpoints
if outbound.BackendRef.Kind != meshExternalServiceKind {
if outbound.BackendRef.Kind != string(common_api.MeshExternalService) {
result.Add(ValidatePort(validators.RootedAt("backendRef").Field("port"), outbound.BackendRef.Port))
}
case len(outbound.Tags) == 0:
Expand All @@ -257,6 +258,33 @@ func validateOutbound(outbound *mesh_proto.Dataplane_Networking_Outbound) valida
return result
}

func validateTransparentProxying(tp *mesh_proto.Dataplane_Networking_TransparentProxying) validators.ValidationError {
var result validators.ValidationError
path := validators.RootedAt("reachableBackends.refs")
if tp != nil && tp.ReachableBackends != nil {
for i, backendRef := range tp.ReachableBackends.Refs {
switch backendRef.Kind {
case string(common_api.MeshMultiZoneService), string(common_api.MeshService), string(common_api.MeshExternalService):
default:
result.AddViolationAt(path.Index(i).Field("kind"), fmt.Sprintf("invalid value. Available values are: %s", strings.Join(maps.SortedKeys(allowedKinds), ",")))
}
if backendRef.Name != "" {
result.AddErrorAt(path.Index(i).Field("name"), validateIdentifier(backendRef.Name, identifierRegexp, identifierErrMsg))
}
if backendRef.Name == "" && backendRef.Namespace == "" && len(backendRef.Labels) == 0 {
result.AddViolationAt(path.Index(i).Field("name"), "name or labels are required")
}
if backendRef.Name == "" && backendRef.Namespace != "" {
result.AddViolationAt(path.Index(i).Field("name"), "name is required, when namespace is defined")
}
if (backendRef.Name != "" || backendRef.Namespace != "") && len(backendRef.Labels) > 0 {
result.AddViolationAt(path.Index(i).Field("labels"), "labels cannot be defined when name is specified")
}
}
}
return result
}

func validateGateway(gateway *mesh_proto.Dataplane_Networking_Gateway) validators.ValidationError {
var result validators.ValidationError

Expand Down
78 changes: 77 additions & 1 deletion pkg/core/resources/apis/mesh/dataplane_validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,29 @@ var _ = Describe("Dataplane", func() {
kind: MeshExternalService
name: xyz`,
),
Entry("dataplane with reachableBackendRefs", `
type: Dataplane
name: dp-1
mesh: default
networking:
address: 192.168.0.1
inbound:
- port: 8080
tags:
kuma.io/service: backend
version: "1"
transparentProxying:
reachableBackends:
refs:
- kind: MeshService
name: a
- kind: MeshExternalService
name: es
namespace: es1
- kind: MeshService
labels:
kuma.io/test: abc`,
),
)

type testCase struct {
Expand Down Expand Up @@ -1213,7 +1236,7 @@ var _ = Describe("Dataplane", func() {
expected: `
violations:
- field: networking.outbound[0].backendRef.kind
message: 'invalid value. Available values are: MeshExternalService,MeshService'
message: 'invalid value. Available values are: MeshExternalService,MeshMultiZoneService,MeshService'
- field: networking.outbound[0].backendRef.name
message: cannot be empty
- field: networking.outbound[0].backendRef.port
Expand Down Expand Up @@ -1256,5 +1279,58 @@ var _ = Describe("Dataplane", func() {
- field: networking.outbound[1].backendRef
message: both backendRef and tags/service cannot be defined`,
}),
Entry("transparent proxy with reachable backend refs", testCase{
dataplane: `
type: Dataplane
name: dp-1
mesh: default
networking:
address: 192.168.0.1
inbound:
- port: 8080
servicePort: 7777
address: 192.168.0.1
tags:
kuma.io/service: backend
version: "1"
transparentProxying:
reachableBackends:
refs:
- kind: Something
name: first
labels:
kuma.io/test: test
- kind: MeshService
name: second
namespace: not-valid
labels:
kuma.io/test: test
- kind: MeshService
name: third
labels:
kuma.io/test: test
- kind: MeshService
name: first$-.kuma
- kind: MeshService
- kind: MeshService
namespace: xyz
`,
expected: `
violations:
- field: networking.transparentProxing.reachableBackends.refs[0].kind
message: 'invalid value. Available values are: MeshExternalService,MeshMultiZoneService,MeshService'
- field: networking.transparentProxing.reachableBackends.refs[0].labels
message: labels cannot be defined when name is specified
- field: networking.transparentProxing.reachableBackends.refs[1].labels
message: labels cannot be defined when name is specified
- field: networking.transparentProxing.reachableBackends.refs[2].labels
message: labels cannot be defined when name is specified
- field: networking.transparentProxing.reachableBackends.refs[3].name
message: invalid characters. A lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character
- field: networking.transparentProxing.reachableBackends.refs[4].name
message: name or labels are required
- field: networking.transparentProxing.reachableBackends.refs[5].name
message: name is required, when namespace is defined`,
}),
)
})
Loading

0 comments on commit 09b7fb3

Please sign in to comment.