Skip to content

Commit

Permalink
feat(kuma-cp): mesh proxy patch xds (#5604)
Browse files Browse the repository at this point in the history
Signed-off-by: Jakub Dyszkiewicz <[email protected]>
  • Loading branch information
jakubdyszkiewicz authored Jan 13, 2023
1 parent b81a9ac commit 4b04a60
Show file tree
Hide file tree
Showing 19 changed files with 3,255 additions and 7 deletions.
6 changes: 4 additions & 2 deletions docs/guides/new-policies.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ The output of the tool will tell you where the important files are!

## Add plugin name to the configuration

Enabled plugin configuration is in `pkg/plugins/policies/policies.go`. Plugins name is equals to `KumactlArg` in file `zz_generated.resource.go`. It's important to place the plugin in the correct place because the order of executions is important.
To enable policy you need to adjust configuration of two places:
* Remove `+kuma:policy:skip_registration=true` from your policy schema.
* `pkg/plugins/policies/policies.go`. Plugins name is equals to `KumactlArg` in file `zz_generated.resource.go`. It's important to place the plugin in the correct place because the order of executions is important.

## How to map API to a Go struct

Expand Down Expand Up @@ -86,4 +88,4 @@ type SomeStruct struct {
type SomeStruct struct {
MyField *ItemType `json"myField,omitempty"`
}
```
```
70 changes: 70 additions & 0 deletions pkg/plugins/policies/meshproxypatch/plugin/v1alpha1/cluster_mod.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package v1alpha1

import (
envoy_cluster "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
envoy_resource "github.com/envoyproxy/go-control-plane/pkg/resource/v3"
"github.com/pkg/errors"

core_xds "github.com/kumahq/kuma/pkg/core/xds"
api "github.com/kumahq/kuma/pkg/plugins/policies/meshproxypatch/api/v1alpha1"
util_proto "github.com/kumahq/kuma/pkg/util/proto"
)

type clusterModificator api.ClusterMod

func (c *clusterModificator) apply(resources *core_xds.ResourceSet) error {
clusterMod := &envoy_cluster.Cluster{}
if c.Value != nil {
if err := util_proto.FromYAML([]byte(*c.Value), clusterMod); err != nil {
return err
}
}
switch c.Operation {
case api.ModOpAdd:
c.add(resources, clusterMod)
case api.ModOpRemove:
c.remove(resources)
case api.ModOpPatch:
c.patch(resources, clusterMod)
default:
return errors.Errorf("invalid operation: %s", c.Operation)
}
return nil
}

func (c *clusterModificator) patch(resources *core_xds.ResourceSet, clusterMod *envoy_cluster.Cluster) {
for _, cluster := range resources.Resources(envoy_resource.ClusterType) {
if c.clusterMatches(cluster) {
util_proto.Merge(cluster.Resource, clusterMod)
}
}
}

func (c *clusterModificator) remove(resources *core_xds.ResourceSet) {
for name, resource := range resources.Resources(envoy_resource.ClusterType) {
if c.clusterMatches(resource) {
resources.Remove(envoy_resource.ClusterType, name)
}
}
}

func (c *clusterModificator) add(resources *core_xds.ResourceSet, clusterMod *envoy_cluster.Cluster) *core_xds.ResourceSet {
return resources.Add(&core_xds.Resource{
Name: clusterMod.Name,
Origin: Origin,
Resource: clusterMod,
})
}

func (c *clusterModificator) clusterMatches(cluster *core_xds.Resource) bool {
if c.Match == nil {
return true
}
if c.Match.Name != nil && *c.Match.Name != cluster.Name {
return false
}
if c.Match.Origin != nil && *c.Match.Origin != cluster.Origin {
return false
}
return true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
package v1alpha1_test

import (
envoy_cluster "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"sigs.k8s.io/yaml"

core_xds "github.com/kumahq/kuma/pkg/core/xds"
api "github.com/kumahq/kuma/pkg/plugins/policies/meshproxypatch/api/v1alpha1"
plugin "github.com/kumahq/kuma/pkg/plugins/policies/meshproxypatch/plugin/v1alpha1"
util_proto "github.com/kumahq/kuma/pkg/util/proto"
"github.com/kumahq/kuma/pkg/xds/generator"
)

var _ = Describe("Cluster modifications", func() {

type testCase struct {
clusters []string
modifications []string
expected string
}

DescribeTable("should apply modifications",
func(given testCase) {
// given
set := core_xds.NewResourceSet()
for _, clusterYAML := range given.clusters {
cluster := &envoy_cluster.Cluster{}
err := util_proto.FromYAML([]byte(clusterYAML), cluster)
Expect(err).ToNot(HaveOccurred())
set.Add(&core_xds.Resource{
Name: cluster.Name,
Origin: generator.OriginInbound,
Resource: cluster,
})
}

var mods []api.Modification
for _, modificationYAML := range given.modifications {
modification := api.Modification{}
err := yaml.Unmarshal([]byte(modificationYAML), &modification)
Expect(err).ToNot(HaveOccurred())
mods = append(mods, modification)
}

// when
err := plugin.ApplyMods(set, mods)

// then
Expect(err).ToNot(HaveOccurred())
resp, err := set.List().ToDeltaDiscoveryResponse()
Expect(err).ToNot(HaveOccurred())
actual, err := util_proto.ToYAML(resp)
Expect(err).ToNot(HaveOccurred())
Expect(actual).To(MatchYAML(given.expected))
},
Entry("should add cluster", testCase{
modifications: []string{`
cluster:
operation: Add
value: |
edsClusterConfig:
edsConfig:
ads: {}
name: test:cluster
type: EDS`,
},
expected: `
resources:
- name: test:cluster
resource:
'@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
edsClusterConfig:
edsConfig:
ads: {}
name: test:cluster
type: EDS`,
}),
Entry("should replace cluster", testCase{
clusters: []string{
`
connectTimeout: 5s
lbPolicy: CLUSTER_PROVIDED
name: test:cluster
type: ORIGINAL_DST`,
},
modifications: []string{
`
cluster:
operation: Add
value: |
edsClusterConfig:
edsConfig:
ads: {}
name: test:cluster
type: EDS`,
},
expected: `
resources:
- name: test:cluster
resource:
'@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
edsClusterConfig:
edsConfig:
ads: {}
name: test:cluster
type: EDS`,
}),
Entry("should remove cluster matching all", testCase{
clusters: []string{
`
connectTimeout: 5s
lbPolicy: CLUSTER_PROVIDED
name: test:cluster
type: ORIGINAL_DST`,
},
modifications: []string{
`
cluster:
operation: Remove`,
},
expected: `{}`,
}),
Entry("should remove cluster matching name", testCase{
clusters: []string{
`
connectTimeout: 5s
lbPolicy: CLUSTER_PROVIDED
name: test:cluster
type: ORIGINAL_DST`,
`
connectTimeout: 5s
lbPolicy: CLUSTER_PROVIDED
name: test:cluster2
type: ORIGINAL_DST`,
},
modifications: []string{
`
cluster:
operation: Remove
match:
name: test:cluster`,
},
expected: `
resources:
- name: test:cluster2
resource:
'@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
connectTimeout: 5s
lbPolicy: CLUSTER_PROVIDED
name: test:cluster2
type: ORIGINAL_DST`,
}),
Entry("should remove all inbound clusters", testCase{
clusters: []string{
`
connectTimeout: 5s
lbPolicy: CLUSTER_PROVIDED
name: test:cluster
type: ORIGINAL_DST`,
},
modifications: []string{
`
cluster:
operation: Remove
match:
origin: inbound`,
},
expected: `{}`,
}),
Entry("should patch cluster matching name", testCase{
clusters: []string{
`
lbPolicy: CLUSTER_PROVIDED
name: test:cluster
outlierDetection:
enforcingConsecutive5xx: 100
enforcingConsecutiveGatewayFailure: 0
enforcingConsecutiveLocalOriginFailure: 0
enforcingFailurePercentage: 0
enforcingSuccessRate: 0
type: ORIGINAL_DST`,
},
modifications: []string{
`
cluster:
operation: Patch
match:
name: test:cluster
value: |
connectTimeout: 5s
httpProtocolOptions:
acceptHttp10: true
outlierDetection:
enforcingSuccessRate: 100`,
},
expected: `
resources:
- name: test:cluster
resource:
'@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
connectTimeout: 5s
httpProtocolOptions:
acceptHttp10: true
lbPolicy: CLUSTER_PROVIDED
name: test:cluster
outlierDetection:
enforcingConsecutive5xx: 100
enforcingConsecutiveGatewayFailure: 0
enforcingConsecutiveLocalOriginFailure: 0
enforcingFailurePercentage: 0
enforcingSuccessRate: 100
type: ORIGINAL_DST`,
}),
)
})
Loading

0 comments on commit 4b04a60

Please sign in to comment.