Skip to content

Commit

Permalink
connectivity: Add local redirect policy tests
Browse files Browse the repository at this point in the history
Signed-off-by: Aditi Ghag <[email protected]>
  • Loading branch information
aditighag committed May 30, 2024
1 parent e02874c commit 1d0736c
Show file tree
Hide file tree
Showing 9 changed files with 315 additions and 8 deletions.
1 change: 1 addition & 0 deletions connectivity/builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ func concurrentTests(connTests []*check.ConnectivityTest) error {
podToK8sOnControlplane{},
podToControlplaneHostCidr{},
podToK8sOnControlplaneCidr{},
localRedirectPolicy{},
}
return injectTests(tests, connTests...)
}
Expand Down
39 changes: 39 additions & 0 deletions connectivity/builder/local_redirect_policy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Cilium

package builder

import (
"github.com/cilium/cilium-cli/connectivity/check"
"github.com/cilium/cilium-cli/connectivity/tests"
"github.com/cilium/cilium-cli/utils/features"
)

type localRedirectPolicy struct{}

func (t localRedirectPolicy) build(ct *check.ConnectivityTest, _ map[string]string) {
newTest("lrp", ct).
WithCiliumLocalRedirectPolicy(check.CiliumLocalRedirectPolicyParams{
Name: "lrp-addr-matcher",
SkipRedirectFromBackend: false,
}).
WithCiliumLocalRedirectPolicy(check.CiliumLocalRedirectPolicyParams{
Name: "lrp-addr-matcher-skip-redirect",
SkipRedirectFromBackend: true,
}).
WithFeatureRequirements(features.RequireEnabled(features.LocalRedirectPolicy)).
WithFeatureRequirements(features.RequireEnabled(features.KPRSocketLB)).
WithScenarios(
tests.LRP(false),
tests.LRP(true),
).
WithExpectations(func(a *check.Action) (egress, ingress check.Result) {
if a.Name() == "local-redirect-policy-skip-redirect-from-backend" {
if a.Source().HasLabel("other", "lrp-backend") {
return check.ResultCurlHTTPError, check.ResultNone
}
return check.ResultOK, check.ResultNone
}
return check.ResultOK, check.ResultNone
})
}
21 changes: 21 additions & 0 deletions connectivity/builder/manifests/local-redirect-policy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
apiVersion: "cilium.io/v2"
kind: CiliumLocalRedirectPolicy
metadata:
name: # set by the check package in WithCiliumLocalRedirectPolicy()
spec:
redirectFrontend:
addressMatcher:
ip: "169.254.169.254"
toPorts:
- port: "8080"
protocol: TCP
redirectBackend:
localEndpointSelector:
matchLabels:
io.kubernetes.pod.namespace: cilium-test
kind: lrp
toPorts:
- port: "8080"
name: "tcp-8080""
protocol: TCP
6 changes: 6 additions & 0 deletions connectivity/check/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ type ConnectivityTest struct {
ingressService map[string]Service
k8sService Service
externalWorkloads map[string]ExternalWorkload
lrpBackendPods map[string]Pod

hostNetNSPodsByNode map[string]Pod
secondaryNetworkNodeIPv4 map[string]string // node name => secondary ip
Expand Down Expand Up @@ -203,6 +204,7 @@ func NewConnectivityTest(client *k8s.Client, p Parameters, version string, logge
echoExternalPods: make(map[string]Pod),
clientPods: make(map[string]Pod),
clientCPPods: make(map[string]Pod),
lrpBackendPods: map[string]Pod{},
perfClientPods: []Pod{},
perfServerPod: []Pod{},
PerfResults: []common.PerfSummary{},
Expand Down Expand Up @@ -1115,6 +1117,10 @@ func (ct *ConnectivityTest) EchoPods() map[string]Pod {
return ct.echoPods
}

func (ct *ConnectivityTest) LrpBackendPods() map[string]Pod {
return ct.lrpBackendPods
}

// EchoServices returns all the non headless services
func (ct *ConnectivityTest) EchoServices() map[string]Service {
svcs := map[string]Service{}
Expand Down
51 changes: 51 additions & 0 deletions connectivity/check/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ const (
kindEchoExternalNodeName = "echo-external-node"
kindClientName = "client"
kindPerfName = "perf"
lrpBackendDeploymentName = "lrp-backend"
kindLrpName = "lrp"

hostNetNSDeploymentName = "host-netns"
hostNetNSDeploymentNameNonCilium = "host-netns-non-cilium" // runs on non-Cilium test nodes
Expand Down Expand Up @@ -924,6 +926,38 @@ func (ct *ConnectivityTest) deploy(ctx context.Context) error {
}
}
}

if ct.Features[features.LocalRedirectPolicy].Enabled {
containerPort := 8080
lrpBackendDeployment := newDeployment(deploymentParameters{
Name: lrpBackendDeploymentName,
Kind: kindLrpName,
Image: ct.params.JSONMockImage,
NamedPort: "tcp-8080",
Port: containerPort,
Affinity: &corev1.Affinity{
PodAffinity: &corev1.PodAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: []corev1.PodAffinityTerm{
{
LabelSelector: &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{Key: "name", Operator: metav1.LabelSelectorOpIn, Values: []string{clientDeploymentName}},
},
},
TopologyKey: corev1.LabelHostname,
},
},
},
},
ReadinessProbe: newLocalReadinessProbe(containerPort, "/"),
Labels: map[string]string{"other": "lrp-backend"},
Annotations: ct.params.DeploymentAnnotations.Match(lrpBackendDeploymentName),
})
_, err = ct.clients.src.CreateDeployment(ctx, ct.params.TestNamespace, lrpBackendDeployment, metav1.CreateOptions{})
if err != nil {
return fmt.Errorf("unable to create deployment %s: %s", lrpBackendDeployment, err)
}
}
return nil
}

Expand Down Expand Up @@ -1172,6 +1206,23 @@ func (ct *ConnectivityTest) validateDeployment(ctx context.Context) error {
return nil
}

if ct.Features[features.LocalRedirectPolicy].Enabled {
lrpPods, err := ct.client.ListPods(ctx, ct.params.TestNamespace, metav1.ListOptions{LabelSelector: "kind=" + kindLrpName})
if err != nil {
return fmt.Errorf("unable to list lrp pods: %w", err)
}
for _, lrpPod := range lrpPods.Items {
_, hasLabel := lrpPod.GetLabels()["lrp-backend"]
if hasLabel {
ct.lrpBackendPods[lrpPod.Name] = Pod{
K8sClient: ct.client,
Pod: lrpPod.DeepCopy(),
}
}
}
return nil
}

clientPods, err := ct.client.ListPods(ctx, ct.params.TestNamespace, metav1.ListOptions{LabelSelector: "kind=" + kindClientName})
if err != nil {
return fmt.Errorf("unable to list client pods: %s", err)
Expand Down
57 changes: 56 additions & 1 deletion connectivity/check/peer.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import (
"net/url"
"strconv"

corev1 "k8s.io/api/core/v1"

"github.com/cilium/cilium/api/v1/flow"
ciliumv2 "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2"
corev1 "k8s.io/api/core/v1"

"github.com/cilium/cilium-cli/k8s"
"github.com/cilium/cilium-cli/utils/features"
Expand Down Expand Up @@ -491,6 +492,60 @@ func (he httpEndpoint) FlowFilters() []*flow.FlowFilter {
return nil
}

type LRPFrontend struct {
name string
ip string
port string
}

func NewLRPFrontend(frontend ciliumv2.RedirectFrontend) *LRPFrontend {
var lf LRPFrontend
if f := frontend.AddressMatcher; f != nil {
lf.ip = f.IP
lf.port = f.ToPorts[0].Port

return &lf
}

return nil
}

func (l LRPFrontend) Name() string {
return l.name
}

func (l LRPFrontend) Scheme() string {
return ""
}

func (l LRPFrontend) Path() string {
return ""
}

func (l LRPFrontend) Address(features.IPFamily) string {
return l.ip
}

func (l LRPFrontend) Port() uint32 {
p, err := strconv.Atoi(l.port)
if err != nil {
return 0
}
return uint32(p)
}

func (l LRPFrontend) HasLabel(string, string) bool {
return false
}

func (l LRPFrontend) Labels() map[string]string {
return nil
}

func (l LRPFrontend) FlowFilters() []*flow.FlowFilter {
return nil
}

// EchoIPPod is a Kubernetes Pod that prints back the client IP, acting as a peer in a connectivity test.
type EchoIPPod struct {
Pod
Expand Down
18 changes: 15 additions & 3 deletions connectivity/check/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,17 @@ import (
"sync"
"time"

flowpb "github.com/cilium/cilium/api/v1/flow"
ciliumv2 "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2"
"github.com/cilium/cilium/pkg/k8s/client/clientset/versioned/scheme"
networkingv1 "k8s.io/api/networking/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
clientsetscheme "k8s.io/client-go/kubernetes/scheme"

flowpb "github.com/cilium/cilium/api/v1/flow"
ciliumv2 "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2"
"github.com/cilium/cilium/pkg/k8s/client/clientset/versioned/scheme"

"github.com/cilium/cilium-cli/defaults"
"github.com/cilium/cilium-cli/k8s"
)
Expand Down Expand Up @@ -447,6 +448,11 @@ func (t *Test) addCEGPs(cegps ...*ciliumv2.CiliumEgressGatewayPolicy) (err error
return err
}

func (t *Test) addCLRPs(clrps ...*ciliumv2.CiliumLocalRedirectPolicy) (err error) {
t.clrps, err = RegisterPolicy(t.clrps, clrps...)
return err
}

func sumMap(m map[string]int) int {
sum := 0
for _, v := range m {
Expand Down Expand Up @@ -722,3 +728,9 @@ func parseK8SPolicyYAML(policy string) (policies []*networkingv1.NetworkPolicy,
func parseCiliumEgressGatewayPolicyYAML(policy string) (cegps []*ciliumv2.CiliumEgressGatewayPolicy, err error) {
return ParsePolicyYAML[*ciliumv2.CiliumEgressGatewayPolicy](policy, scheme.Scheme)
}

// parseCiliumLocalRedirectPolicyYAML decodes policy yaml into a slice of
// CiliumLocalRedirectPolicies.
func parseCiliumLocalRedirectPolicyYAML(policy string) (clrp []*ciliumv2.CiliumLocalRedirectPolicy, err error) {
return ParsePolicyYAML[*ciliumv2.CiliumLocalRedirectPolicy](policy, scheme.Scheme)
}
51 changes: 47 additions & 4 deletions connectivity/check/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,6 @@ import (
"time"

"github.com/blang/semver/v4"
k8sConst "github.com/cilium/cilium/pkg/k8s/apis/cilium.io"
ciliumv2 "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2"
"github.com/cilium/cilium/pkg/policy/api"
"github.com/cilium/cilium/pkg/versioncheck"
"github.com/cloudflare/cfssl/cli/genkey"
"github.com/cloudflare/cfssl/config"
"github.com/cloudflare/cfssl/csr"
Expand All @@ -29,6 +25,11 @@ import (
networkingv1 "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

k8sConst "github.com/cilium/cilium/pkg/k8s/apis/cilium.io"
ciliumv2 "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2"
"github.com/cilium/cilium/pkg/policy/api"
"github.com/cilium/cilium/pkg/versioncheck"

"github.com/cilium/cilium-cli/defaults"
"github.com/cilium/cilium-cli/sysdump"
"github.com/cilium/cilium-cli/utils/features"
Expand Down Expand Up @@ -121,6 +122,9 @@ type Test struct {
// Cilium Egress Gateway Policies active during this test.
cegps map[string]*ciliumv2.CiliumEgressGatewayPolicy

// Cilium Local Redirect Policies active during this test.
clrps map[string]*ciliumv2.CiliumLocalRedirectPolicy

// Secrets that have to be present during the test.
secrets map[string]*corev1.Secret

Expand Down Expand Up @@ -537,6 +541,41 @@ func (t *Test) WithK8SPolicy(policy string) *Test {
return t
}

// CiliumLocalRedirectPolicyParams is used to configure a CiliumLocalRedirectPolicy template.
type CiliumLocalRedirectPolicyParams struct {
// Name controls the name of the policy
Name string

// SkipRedirectFromBackend is the flag set in the policy spec.
SkipRedirectFromBackend bool
}

func (t *Test) WithCiliumLocalRedirectPolicy(params CiliumLocalRedirectPolicyParams) *Test {
pl, err := parseCiliumLocalRedirectPolicyYAML(params.Name)
if err != nil {
t.Fatalf("Parsing local redirect policy YAML: %s", err)
}

// Change the default test namespace as required.
for i := range pl {
pl[i].Namespace = t.ctx.params.TestNamespace

// Set the policy name
pl[i].Name = params.Name

// Set the flag from params.
pl[i].Spec.SkipRedirectFromBackend = params.SkipRedirectFromBackend
}

if err := t.addCLRPs(pl...); err != nil {
t.Fatalf("Adding CLRPs to cilium local redirect policy context: %s", err)
}

t.WithFeatureRequirements(features.RequireEnabled(features.LocalRedirectPolicy))

return t
}

type ExcludedCIDRsKind int

const (
Expand Down Expand Up @@ -935,3 +974,7 @@ func (t *Test) CiliumClusterwideNetworkPolicies() map[string]*ciliumv2.CiliumClu
func (t *Test) KubernetesNetworkPolicies() map[string]*networkingv1.NetworkPolicy {
return t.knps
}

func (t *Test) CiliumLocalRedirectPolicies() map[string]*ciliumv2.CiliumLocalRedirectPolicy {
return t.clrps
}
Loading

0 comments on commit 1d0736c

Please sign in to comment.