Skip to content

Commit

Permalink
connectivity: Introduce local redirect policy tests
Browse files Browse the repository at this point in the history
Tests LRP connectivity scenarios with a configured
skipRedirectFromBackend flag:
 - client pod to LRP frontend
 - LRP backend to LRP frontend

 Signed-off-by: Aditi Ghag <[email protected]>

Signed-off-by: Aditi Ghag <[email protected]>
  • Loading branch information
aditighag committed Jun 4, 2024
1 parent c5bb958 commit 1a7cc8b
Show file tree
Hide file tree
Showing 11 changed files with 504 additions and 13 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
53 changes: 53 additions & 0 deletions connectivity/builder/local_redirect_policy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Cilium

package builder

import (
_ "embed"

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

var (
//go:embed manifests/local-redirect-policy.yaml
localRedirectPolicyYAML string
)

type localRedirectPolicy struct{}

func (t localRedirectPolicy) build(ct *check.ConnectivityTest, _ map[string]string) {
lrpFrontendIP := "169.254.169.254"
lrpFrontendIPSkipRedirect := "169.254.169.255"
newTest("lrp", ct).
WithCiliumLocalRedirectPolicy(check.CiliumLocalRedirectPolicyParams{
Policy: localRedirectPolicyYAML,
Name: "lrp-address-matcher",
FrontendIP: lrpFrontendIP,
SkipRedirectFromBackend: false,
}).
WithCiliumLocalRedirectPolicy(check.CiliumLocalRedirectPolicyParams{
Policy: localRedirectPolicyYAML,
Name: "lrp-address-matcher-skip-redirect-from-backend",
FrontendIP: lrpFrontendIPSkipRedirect,
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.Scenario().Name() == "local-redirect-policy-skip-redirect-from-backend" {
if a.Source().HasLabel("role", "lrp-backend") &&
a.Destination().Address(features.IPFamilyV4) == lrpFrontendIPSkipRedirect {
return check.ResultCurlTimeout, check.ResultNone
}
return check.ResultOK, check.ResultNone
}
return check.ResultOK, check.ResultNone
})
}
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: # set by the check package in WithCiliumLocalRedirectPolicy()
toPorts:
- port: "80"
name: "tcp"
protocol: TCP
redirectBackend:
localEndpointSelector:
matchLabels:
role: lrp-backend
toPorts:
- port: "8080"
name: "tcp-8080"
protocol: TCP
skipRedirectFromBackend: # set by the check package in WithCiliumLocalRedirectPolicy()
20 changes: 20 additions & 0 deletions connectivity/builder/manifests/local-redirect-policy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
apiVersion: cilium.io/v2
kind: CiliumLocalRedirectPolicy
metadata:
name: lrp-addr-matcher
spec:
redirectFrontend:
addressMatcher:
ip: "169.254.169.254"
toPorts:
- port: "8080"
name: "tcp"
protocol: TCP
redirectBackend:
localEndpointSelector:
matchLabels:
role: lrp-backend
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: make(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
42 changes: 42 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,29 @@ func (ct *ConnectivityTest) deploy(ctx context.Context) error {
}
}
}

if ct.Features[features.LocalRedirectPolicy].Enabled {
ct.Logf("✨ [%s] Deploying lrp-backend deployment...", ct.clients.src.ClusterName())
containerPort := 8080
lrpBackendDeployment := newDeployment(deploymentParameters{
Name: lrpBackendDeploymentName,
Kind: kindLrpName,
Image: ct.params.JSONMockImage,
NamedPort: "tcp-8080",
Port: containerPort,
ReadinessProbe: newLocalReadinessProbe(containerPort, "/"),
Labels: map[string]string{"role": "lrp-backend"},
Annotations: ct.params.DeploymentAnnotations.Match(lrpBackendDeploymentName),
})
_, err = ct.clients.src.CreateServiceAccount(ctx, ct.params.TestNamespace, k8s.NewServiceAccount(lrpBackendDeploymentName), metav1.CreateOptions{})
if err != nil {
return fmt.Errorf("unable to create service account %s: %s", lrpBackendDeployment, err)
}
_, 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 +1197,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()["role"]
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 "http"
}

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
Loading

0 comments on commit 1a7cc8b

Please sign in to comment.