-
Notifications
You must be signed in to change notification settings - Fork 337
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(rules): organize code in the packages, prepare for inbound r…
…ules (#12559) ## Motivation * with the introduction of inbound rules, a single file `rules.go` is insufficient * new inbound rules are going to introduce a new entry type (i.e. `to[i]` has `targetRef` and `default` fields, while `rules[i]` is going to have `default`, `matches`, `targetRef` fields). It's easier to use generics, like ```go type WithPolicyAttributes[T any] struct { Entry T TopLevel common_api.TargetRef Meta core_model.ResourceMeta RuleIndex int } ``` to share the code between inbound and outbound rules (see packages `merge`, `sort`, `common`) Signed-off-by: Ilya Lobkov <[email protected]>
- Loading branch information
1 parent
a00b2e0
commit 820494c
Showing
213 changed files
with
1,521 additions
and
1,237 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package common | ||
|
||
import core_model "github.com/kumahq/kuma/pkg/core/resources/model" | ||
|
||
// Cast attempts to cast a slice of core_model.Resource to a slice of a specific type T. | ||
// It returns the casted slice and a boolean indicating whether the cast was successful. | ||
// If any element in the slice cannot be cast to the specified type, the function returns nil and false. | ||
func Cast[T any](rs []core_model.Resource) ([]T, bool) { | ||
var rv []T | ||
for _, r := range rs { | ||
if casted, ok := r.GetSpec().(T); !ok { | ||
return nil, false | ||
} else { | ||
rv = append(rv, casted) | ||
} | ||
} | ||
return rv, true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package common | ||
|
||
import ( | ||
common_api "github.com/kumahq/kuma/api/common/v1alpha1" | ||
core_model "github.com/kumahq/kuma/pkg/core/resources/model" | ||
meshhttproute_api "github.com/kumahq/kuma/pkg/plugins/policies/meshhttproute/api/v1alpha1" | ||
meshtcproute_api "github.com/kumahq/kuma/pkg/plugins/policies/meshtcproute/api/v1alpha1" | ||
) | ||
|
||
type Origin struct { | ||
Resource core_model.ResourceMeta | ||
// RuleIndex is an index in the 'to[]' array, so we could unambiguously detect what to-item contributed to the final conf. | ||
// Especially useful when to-item uses `targetRef.Labels`, because there is no obvious matching between the specific resource | ||
// in `ResourceRule.Resource` and to-item. | ||
RuleIndex int | ||
} | ||
|
||
type BackendRefOriginIndex map[common_api.MatchesHash]int | ||
|
||
var EmptyMatches common_api.MatchesHash = "" | ||
|
||
func (originIndex BackendRefOriginIndex) Update(conf interface{}, newIndex int) { | ||
switch conf := conf.(type) { | ||
case meshtcproute_api.Rule: | ||
if conf.Default.BackendRefs != nil { | ||
originIndex[EmptyMatches] = newIndex | ||
} | ||
case meshhttproute_api.PolicyDefault: | ||
for _, rule := range conf.Rules { | ||
if rule.Default.BackendRefs != nil { | ||
hash := meshhttproute_api.HashMatches(rule.Matches) | ||
originIndex[hash] = newIndex | ||
} | ||
} | ||
default: | ||
return | ||
} | ||
} | ||
|
||
func Origins[B BaseEntry, T interface { | ||
PolicyAttributes | ||
Entry[B] | ||
}](items []T, withRuleIndex bool) ([]Origin, BackendRefOriginIndex) { | ||
var rv []Origin | ||
|
||
type keyType struct { | ||
core_model.ResourceKey | ||
ruleIndex int | ||
} | ||
key := func(policyItem T) keyType { | ||
k := keyType{ | ||
ResourceKey: core_model.MetaToResourceKey(policyItem.GetResourceMeta()), | ||
} | ||
if withRuleIndex { | ||
k.ruleIndex = policyItem.GetRuleIndex() | ||
} | ||
return k | ||
} | ||
set := map[keyType]struct{}{} | ||
originIndex := BackendRefOriginIndex{} | ||
for _, item := range items { | ||
if _, ok := set[key(item)]; !ok { | ||
originIndex.Update(item.GetEntry().GetDefault(), len(rv)) | ||
rv = append(rv, Origin{Resource: item.GetResourceMeta(), RuleIndex: item.GetRuleIndex()}) | ||
set[key(item)] = struct{}{} | ||
} | ||
} | ||
return rv, originIndex | ||
} |
57 changes: 57 additions & 0 deletions
57
pkg/plugins/policies/core/rules/common/policyattributes.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package common | ||
|
||
import ( | ||
common_api "github.com/kumahq/kuma/api/common/v1alpha1" | ||
core_model "github.com/kumahq/kuma/pkg/core/resources/model" | ||
) | ||
|
||
type PolicyAttributes interface { | ||
GetTopLevel() common_api.TargetRef | ||
GetResourceMeta() core_model.ResourceMeta | ||
GetRuleIndex() int | ||
} | ||
|
||
// Entry is a piece of configuration that is part of a policy. Outbound policies, for example, have a list of entries called 'to'. | ||
// Inbound policies at this moment have a list of entries called 'from'. Entries in 'from' and 'to' have the same type: | ||
// | ||
// type PolicyItem interface { | ||
// GetTargetRef() common_api.TargetRef | ||
// GetDefault() interface{} | ||
// } | ||
// | ||
// But 'from' list of entries is going to be replaced with 'rules' according to docs/madr/decisions/069-inbound-policies.md. | ||
// Entries in 'to' and entries in 'rules' won't have the same type anymore, they're going to have 'ToEntry' and 'RuleEntry' | ||
// types respectively. So, we need to make 'Entry' generic to be able to use it in shared packages like 'sort', 'merge' and 'common'. | ||
type Entry[T BaseEntry] interface { | ||
GetEntry() T | ||
} | ||
|
||
// BaseEntry is a base interface for all entries in policies. Regardless of the type of the entry, | ||
// it should always contain a piece of configuration. | ||
type BaseEntry interface { | ||
GetDefault() interface{} | ||
} | ||
|
||
type WithPolicyAttributes[T any] struct { | ||
Entry T | ||
|
||
TopLevel common_api.TargetRef | ||
Meta core_model.ResourceMeta | ||
RuleIndex int | ||
} | ||
|
||
func (p WithPolicyAttributes[T]) GetTopLevel() common_api.TargetRef { | ||
return p.TopLevel | ||
} | ||
|
||
func (p WithPolicyAttributes[T]) GetResourceMeta() core_model.ResourceMeta { | ||
return p.Meta | ||
} | ||
|
||
func (p WithPolicyAttributes[T]) GetRuleIndex() int { | ||
return p.RuleIndex | ||
} | ||
|
||
func (p WithPolicyAttributes[T]) GetEntry() T { | ||
return p.Entry | ||
} |
115 changes: 115 additions & 0 deletions
115
pkg/plugins/policies/core/rules/common/resolvetargetref.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
package common | ||
|
||
import ( | ||
"strconv" | ||
"strings" | ||
|
||
"github.com/pkg/errors" | ||
|
||
common_api "github.com/kumahq/kuma/api/common/v1alpha1" | ||
mesh_proto "github.com/kumahq/kuma/api/mesh/v1alpha1" | ||
meshservice_api "github.com/kumahq/kuma/pkg/core/resources/apis/meshservice/api/v1alpha1" | ||
core_model "github.com/kumahq/kuma/pkg/core/resources/model" | ||
"github.com/kumahq/kuma/pkg/plugins/policies/core/rules/subsetutils" | ||
) | ||
|
||
type ResourceSection struct { | ||
Resource core_model.Resource | ||
SectionName string | ||
} | ||
|
||
func (rs *ResourceSection) Identifier() core_model.TypedResourceIdentifier { | ||
return UniqueKey(rs.Resource, rs.SectionName) | ||
} | ||
|
||
func UniqueKey(r core_model.Resource, sectionName string) core_model.TypedResourceIdentifier { | ||
return core_model.TypedResourceIdentifier{ | ||
ResourceIdentifier: core_model.NewResourceIdentifier(r), | ||
ResourceType: r.Descriptor().Name, | ||
SectionName: sectionName, | ||
} | ||
} | ||
|
||
func ResolveTargetRef(targetRef common_api.TargetRef, tMeta core_model.ResourceMeta, reader ResourceReader) []*ResourceSection { | ||
if !targetRef.Kind.IsRealResource() { | ||
return nil | ||
} | ||
rtype := core_model.ResourceType(targetRef.Kind) | ||
list := reader.ListOrEmpty(rtype).GetItems() | ||
|
||
var implicitPort uint32 | ||
implicitLabels := map[string]string{} | ||
if targetRef.Kind == common_api.MeshService && targetRef.SectionName == "" { | ||
if name, namespace, port, err := parseService(targetRef.Name); err == nil { | ||
implicitLabels[mesh_proto.KubeNamespaceTag] = namespace | ||
implicitLabels[mesh_proto.DisplayName] = name | ||
implicitPort = port | ||
} | ||
} | ||
|
||
labels := targetRef.Labels | ||
if len(implicitLabels) > 0 { | ||
labels = implicitLabels | ||
} | ||
|
||
if len(labels) > 0 { | ||
var rv []*ResourceSection | ||
trLabels := subsetutils.NewSubset(labels) | ||
for _, r := range list { | ||
rLabels := subsetutils.NewSubset(r.GetMeta().GetLabels()) | ||
var implicitSectionName string | ||
if ms, ok := r.(*meshservice_api.MeshServiceResource); ok && implicitPort != 0 { | ||
for _, port := range ms.Spec.Ports { | ||
if port.Port == implicitPort { | ||
implicitSectionName = port.Name | ||
} | ||
} | ||
} | ||
sn := targetRef.SectionName | ||
if sn == "" { | ||
sn = implicitSectionName | ||
} | ||
if trLabels.IsSubset(rLabels) { | ||
rv = append(rv, &ResourceSection{ | ||
Resource: r, | ||
SectionName: sn, | ||
}) | ||
} | ||
} | ||
return rv | ||
} | ||
|
||
ri := core_model.TargetRefToResourceIdentifier(tMeta, targetRef) | ||
if resource := reader.Get(rtype, ri); resource != nil { | ||
return []*ResourceSection{{ | ||
Resource: resource, | ||
SectionName: targetRef.SectionName, | ||
}} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func parseService(host string) (string, string, uint32, error) { | ||
// split host into <name>_<namespace>_svc_<port> | ||
segments := strings.Split(host, "_") | ||
|
||
var port uint32 | ||
switch len(segments) { | ||
case 4: | ||
p, err := strconv.ParseInt(segments[3], 10, 32) | ||
if err != nil { | ||
return "", "", 0, err | ||
} | ||
port = uint32(p) | ||
case 3: | ||
// service less service names have no port, so we just put the reserved | ||
// one here to note that this service is actually | ||
port = mesh_proto.TCPPortReserved | ||
default: | ||
return "", "", 0, errors.Errorf("service tag in unexpected format") | ||
} | ||
|
||
name, namespace := segments[0], segments[1] | ||
return name, namespace, port, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package common | ||
|
||
import core_model "github.com/kumahq/kuma/pkg/core/resources/model" | ||
|
||
type ResourceReader interface { | ||
Get(resourceType core_model.ResourceType, ri core_model.ResourceIdentifier) core_model.Resource | ||
ListOrEmpty(resourceType core_model.ResourceType) core_model.ResourceList | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.