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

sotw: rlp workflow #893

Open
wants to merge 60 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
65174af
sotw: effective ratelimitpolicy
guicassolato Sep 27, 2024
d08884d
removed unused function to apply rlp overrides
guicassolato Oct 8, 2024
a7823ea
istio extension (WasmPlugin) reconciler
guicassolato Oct 8, 2024
0e78967
fixup: unique limit definitions per scope
guicassolato Oct 8, 2024
93f1cb0
fixup: log error only when indeed there's an error to be logged
guicassolato Oct 8, 2024
1f02216
do not fail when missing kuadrant object
guicassolato Oct 8, 2024
79fcece
fixup: equality between wasmplugins and avoid rebuilding wasm config …
guicassolato Oct 8, 2024
bfb892a
fixup: error comparison
guicassolato Oct 8, 2024
953f2df
cleanup istio extension objects when it cannot calculate effective po…
guicassolato Oct 8, 2024
0107f3c
refactor: removal of SortablePolicy for sorting policies objects by c…
guicassolato Oct 9, 2024
6bebc06
remove no longer relevant integration test case
guicassolato Oct 9, 2024
bc0457e
fixup: avoid updating invalid rate limit policies to 'accepted' on ev…
guicassolato Oct 9, 2024
1353b13
fixup: continue istio extension workflow when it fails for a given ga…
guicassolato Oct 10, 2024
36c9022
Remove unnused event recorder from base reconciler
guicassolato Oct 10, 2024
69d778e
Istio rate limit cluster reconciler
guicassolato Oct 10, 2024
5045079
enable Istio-related rate limit tasks only when Istio is installed
guicassolato Oct 10, 2024
4143f40
ensure at least one hostname per wasm config policy
guicassolato Oct 10, 2024
4b2e0af
bump istio to 1.22
guicassolato Oct 11, 2024
05ce432
Use targetRefs to attach to gateways in the Istio EnvoyFilter and Was…
guicassolato Oct 11, 2024
69997ab
refactor: debug log messages for when Limitador, EnvoyFilter and Wasm…
guicassolato Oct 12, 2024
2b17ab8
sort wasm 'policies' within the wasm plugin config by hostname from m…
guicassolato Oct 12, 2024
13b3601
go fmt: refactor: debug log messages for when Limitador, EnvoyFilter …
guicassolato Oct 12, 2024
899c608
sort wasm 'policies' within the wasm plugin config by hostname and ht…
guicassolato Oct 12, 2024
3d39778
code style: remove unused parameter ctx
guicassolato Oct 12, 2024
0355c4f
fix: unit test: sort wasm 'policies' within the wasm plugin config by…
guicassolato Oct 12, 2024
e25f237
Refactor WasmPlugin reconciliation to reduce repetition with EnvoyExt…
guicassolato Oct 14, 2024
c77b395
envoy gateway rate limit cluster reconciler
guicassolato Oct 14, 2024
58c4733
fix: wrong default GroupKind assumed on Istio policies TargetRefs
guicassolato Oct 15, 2024
c5e3fd0
minor fixes to code comments and log messages
guicassolato Oct 15, 2024
e59dba3
envoy gateway extension reconciler
guicassolato Oct 15, 2024
ae90f92
code style: ratelimit.RateLimitIndex -> Index
guicassolato Oct 15, 2024
8a54c9f
code style: wasm.WasmExtensionName -> ExtensionName
guicassolato Oct 15, 2024
93ce1dc
code style: wasm.WasmRuleBuilderFunc -> RuleBuilderFunc
guicassolato Oct 15, 2024
6643b55
code style: fix grouping of go imports
guicassolato Oct 15, 2024
c5ed145
new structure of the wasm config based on https://github.com/Kuadrant…
guicassolato Oct 15, 2024
cec1622
fix: envoy_gateway_extension_reconciler.go file name
guicassolato Oct 16, 2024
b74e5a8
fix: log messages of envoy patch policy reconciliation
guicassolato Oct 16, 2024
bc98559
rlp enforced condition and consistency in the message when target not…
guicassolato Oct 16, 2024
283ec56
tests: gateway extension reconciler tests resource comparison
guicassolato Oct 16, 2024
4802a4c
more descriptive wasm actionset names
guicassolato Oct 17, 2024
208482b
tests: fix integration tests - order of wasm action sets
guicassolato Oct 17, 2024
bfe3d4c
fixup: should not increment twice on the index of http route match wh…
guicassolato Oct 17, 2024
4e1d26e
tests: fix integration tests - order of wasm action sets (again!)
guicassolato Oct 17, 2024
d713691
back to opaque wasm action set names
guicassolato Oct 17, 2024
2222e0e
remove duplicate GetKuadrantFromTopology func
guicassolato Oct 17, 2024
8af72a3
do not isolate policy-machinery imports in a separate group
guicassolato Oct 17, 2024
9594f17
helper function to extract network objects in a request path
guicassolato Oct 17, 2024
837992c
set owner reference directly when building the desired objects
guicassolato Oct 17, 2024
464386e
only validate policies on create and update events
guicassolato Oct 18, 2024
9a11b6a
update policy status on all kinds of policy-releated event (deleting …
guicassolato Oct 18, 2024
b0e8dcf
use labels on the internal resources created to watch and select them…
guicassolato Oct 18, 2024
62cea07
policy not enforced due to 'not in the path to any existing routes' (…
guicassolato Oct 18, 2024
a6b4ae2
tests: fix integration tests - Istio EnvoyFilter only created if RLP …
guicassolato Oct 18, 2024
8750e88
lint: removed unnused func arg in the tests
guicassolato Oct 18, 2024
1fa2a7c
tests: fix integration tests - Istio WasmPlugin config with correct l…
guicassolato Oct 18, 2024
9e9aedc
check state of the targeted resources to define the policy's enforced…
guicassolato Oct 18, 2024
b4bdabf
re-enable RateLimitPolicy discoverability (PolicyAffected status cond…
guicassolato Oct 18, 2024
16302b6
tests: fix integration tests - common ratelimit workflow tests
guicassolato Oct 18, 2024
bee0baf
refactor: common.NamespacedNameFromLocator func
guicassolato Oct 18, 2024
d5af8ca
hack to isolate test namespaces sharing the same limitador cr
guicassolato Oct 18, 2024
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
200 changes: 200 additions & 0 deletions api/v1/merge_strategies.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
/*
Copyright 2024.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1

import (
"sort"
"strings"

"github.com/kuadrant/policy-machinery/controller"
"github.com/kuadrant/policy-machinery/machinery"
"github.com/samber/lo"
"k8s.io/apimachinery/pkg/runtime"
k8stypes "k8s.io/apimachinery/pkg/types"
)

const (
AtomicMergeStrategy = "atomic"
PolicyRuleMergeStrategy = "merge"
)

type MergeableRule struct {
Spec any
Source string
}

// +kubebuilder:object:generate=false
type MergeablePolicy interface {
machinery.Policy

Rules() map[string]MergeableRule
SetRules(map[string]MergeableRule)
Empty() bool

DeepCopyObject() runtime.Object
}

// AtomicDefaultsMergeStrategy implements a merge strategy that returns the target Policy if it exists,
// otherwise it returns the source Policy.
func AtomicDefaultsMergeStrategy(source, target machinery.Policy) machinery.Policy {
if source == nil {
return target
}

Check warning on line 56 in api/v1/merge_strategies.go

View check run for this annotation

Codecov / codecov/patch

api/v1/merge_strategies.go#L55-L56

Added lines #L55 - L56 were not covered by tests
if target == nil {
return source
}

Check warning on line 59 in api/v1/merge_strategies.go

View check run for this annotation

Codecov / codecov/patch

api/v1/merge_strategies.go#L58-L59

Added lines #L58 - L59 were not covered by tests

mergeableTargetPolicy := target.(MergeablePolicy)

if !mergeableTargetPolicy.Empty() {
return mergeableTargetPolicy.DeepCopyObject().(machinery.Policy)
}

return source.(MergeablePolicy).DeepCopyObject().(machinery.Policy)

Check warning on line 67 in api/v1/merge_strategies.go

View check run for this annotation

Codecov / codecov/patch

api/v1/merge_strategies.go#L67

Added line #L67 was not covered by tests
}

var _ machinery.MergeStrategy = AtomicDefaultsMergeStrategy

// AtomicOverridesMergeStrategy implements a merge strategy that overrides a target Policy with
// a source one.
func AtomicOverridesMergeStrategy(source, _ machinery.Policy) machinery.Policy {
if source == nil {
return nil
}

Check warning on line 77 in api/v1/merge_strategies.go

View check run for this annotation

Codecov / codecov/patch

api/v1/merge_strategies.go#L76-L77

Added lines #L76 - L77 were not covered by tests
return source.(MergeablePolicy).DeepCopyObject().(machinery.Policy)
}

var _ machinery.MergeStrategy = AtomicOverridesMergeStrategy

// PolicyRuleDefaultsMergeStrategy implements a merge strategy that merges a source Policy into a target one
// by keeping the policy rules from the target and adding the ones from the source that do not exist in the target.
func PolicyRuleDefaultsMergeStrategy(source, target machinery.Policy) machinery.Policy {
if source == nil {
return target
}
if target == nil {
return source
}

Check warning on line 91 in api/v1/merge_strategies.go

View check run for this annotation

Codecov / codecov/patch

api/v1/merge_strategies.go#L85-L91

Added lines #L85 - L91 were not covered by tests

sourceMergeablePolicy := source.(MergeablePolicy)
targetMergeablePolicy := target.(MergeablePolicy)

// copy rules from the target
rules := targetMergeablePolicy.Rules()

// add extra rules from the source
for ruleID, rule := range sourceMergeablePolicy.Rules() {
if _, ok := targetMergeablePolicy.Rules()[ruleID]; !ok {
rules[ruleID] = MergeableRule{
Spec: rule.Spec,
Source: source.GetLocator(),
}
}

Check warning on line 106 in api/v1/merge_strategies.go

View check run for this annotation

Codecov / codecov/patch

api/v1/merge_strategies.go#L93-L106

Added lines #L93 - L106 were not covered by tests
}

mergedPolicy := targetMergeablePolicy.DeepCopyObject().(MergeablePolicy)
mergedPolicy.SetRules(rules)
return mergedPolicy

Check warning on line 111 in api/v1/merge_strategies.go

View check run for this annotation

Codecov / codecov/patch

api/v1/merge_strategies.go#L109-L111

Added lines #L109 - L111 were not covered by tests
}

var _ machinery.MergeStrategy = PolicyRuleDefaultsMergeStrategy

// PolicyRuleOverridesMergeStrategy implements a merge strategy that merges a source Policy into a target one
// by using the policy rules from the source and keeping from the target only the policy rules that do not exist in
// the source.
func PolicyRuleOverridesMergeStrategy(source, target machinery.Policy) machinery.Policy {
sourceMergeablePolicy := source.(MergeablePolicy)
targetMergeablePolicy := target.(MergeablePolicy)

// copy rules from the source
rules := sourceMergeablePolicy.Rules()

// add extra rules from the target
for ruleID, rule := range targetMergeablePolicy.Rules() {
if _, ok := sourceMergeablePolicy.Rules()[ruleID]; !ok {
rules[ruleID] = rule
}

Check warning on line 130 in api/v1/merge_strategies.go

View check run for this annotation

Codecov / codecov/patch

api/v1/merge_strategies.go#L119-L130

Added lines #L119 - L130 were not covered by tests
}

mergedPolicy := targetMergeablePolicy.DeepCopyObject().(MergeablePolicy)
mergedPolicy.SetRules(rules)
return mergedPolicy

Check warning on line 135 in api/v1/merge_strategies.go

View check run for this annotation

Codecov / codecov/patch

api/v1/merge_strategies.go#L133-L135

Added lines #L133 - L135 were not covered by tests
}

var _ machinery.MergeStrategy = PolicyRuleOverridesMergeStrategy

func DefaultsMergeStrategy(strategy string) machinery.MergeStrategy {
switch strategy {
case AtomicMergeStrategy:
return AtomicDefaultsMergeStrategy
case PolicyRuleMergeStrategy:
return PolicyRuleDefaultsMergeStrategy
default:
return AtomicDefaultsMergeStrategy

Check warning on line 147 in api/v1/merge_strategies.go

View check run for this annotation

Codecov / codecov/patch

api/v1/merge_strategies.go#L144-L147

Added lines #L144 - L147 were not covered by tests
}
}

func OverridesMergeStrategy(strategy string) machinery.MergeStrategy {
switch strategy {
case AtomicMergeStrategy:
return AtomicOverridesMergeStrategy
case PolicyRuleMergeStrategy:
return PolicyRuleOverridesMergeStrategy
default:
return AtomicOverridesMergeStrategy

Check warning on line 158 in api/v1/merge_strategies.go

View check run for this annotation

Codecov / codecov/patch

api/v1/merge_strategies.go#L155-L158

Added lines #L155 - L158 were not covered by tests
}
}

// EffectivePolicyForPath returns the effective policy for a given path, merging all policies in the path.
// The policies in the path are sorted from the least specific to the most specific.
// Only policies whose predicate returns true are considered.
func EffectivePolicyForPath[T machinery.Policy](path []machinery.Targetable, predicate func(machinery.Policy) bool) *T {
policies := PoliciesInPath(path, predicate)
if len(policies) == 0 {
return nil
}

// map reduces the policies from most specific to least specific, merging them into one effective policy
effectivePolicy := lo.ReduceRight(policies, func(effectivePolicy machinery.Policy, policy machinery.Policy, _ int) machinery.Policy {
return effectivePolicy.Merge(policy)
}, policies[len(policies)-1])

concreteEffectivePolicy, _ := effectivePolicy.(T)
return &concreteEffectivePolicy
}

// OrderedPoliciesForPath gathers all policies in a path sorted from the least specific to the most specific.
// Only policies whose predicate returns true are considered.
func PoliciesInPath(path []machinery.Targetable, predicate func(machinery.Policy) bool) []machinery.Policy {
return lo.FlatMap(path, func(targetable machinery.Targetable, _ int) []machinery.Policy {
policies := lo.FilterMap(targetable.Policies(), func(policy machinery.Policy, _ int) (controller.Object, bool) {
o, object := policy.(controller.Object)
return o, object && predicate(policy)
})
sort.Sort(controller.ObjectsByCreationTimestamp(policies))
return lo.Map(policies, func(policy controller.Object, _ int) machinery.Policy {
p, _ := policy.(machinery.Policy)
return p
})
})
}

func PathID(path []machinery.Targetable) string {
return strings.Join(lo.Map(path, func(t machinery.Targetable, _ int) string {
return strings.TrimPrefix(k8stypes.NamespacedName{Namespace: t.GetNamespace(), Name: t.GetName()}.String(), string(k8stypes.Separator))
}), "|")
}
32 changes: 21 additions & 11 deletions api/v1beta3/groupversion_info.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2021.
Copyright 2024.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand All @@ -14,23 +14,33 @@
limitations under the License.
*/

// Package v1beta3 contains API Schema definitions for the kuadrant v1beta3 API group
// API schema definitions for the Kuadrant v1beta3 API group
// +kubebuilder:object:generate=true
// +groupName=kuadrant.io
package v1beta3

import (
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/scheme"
ctrl "sigs.k8s.io/controller-runtime/pkg/scheme"
)

var (
// GroupVersion is group version used to register these objects
GroupVersion = schema.GroupVersion{Group: "kuadrant.io", Version: "v1beta3"}
// GroupName specifies the group name used to register the objects.
const GroupName = "kuadrant.io"

// SchemeBuilder is used to add go types to the GroupVersionKind scheme
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
// GroupVersion specifies the group and the version used to register the objects.
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1beta3"}

// AddToScheme adds the types in this group-version to the given scheme.
AddToScheme = SchemeBuilder.AddToScheme
)
// SchemeGroupVersion is group version used to register these objects
// Deprecated: use GroupVersion instead.
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1beta3"}

// SchemeBuilder is used to add go types to the GroupVersionKind scheme
var SchemeBuilder = &ctrl.Builder{GroupVersion: GroupVersion}

// AddToScheme adds the types in this group-version to the given scheme.
var AddToScheme = SchemeBuilder.AddToScheme

// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()

Check warning on line 45 in api/v1beta3/groupversion_info.go

View check run for this annotation

Codecov / codecov/patch

api/v1beta3/groupversion_info.go#L44-L45

Added lines #L44 - L45 were not covered by tests
}
Loading
Loading