Skip to content

Commit 54d6ce3

Browse files
authored
Merge pull request #5220 from qinqon/kv-e2e-integrate-providers
Adapt e2e kind provider for kubevirt localnet tests
2 parents 9ac781e + 956981a commit 54d6ce3

File tree

20 files changed

+610
-786
lines changed

20 files changed

+610
-786
lines changed

contrib/kind-common

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -388,30 +388,7 @@ install_kubevirt() {
388388

389389
local kubevirt_stable_release_url=$(get_kubevirt_release_url "stable")
390390
kubectl -n kubevirt patch kubevirt kubevirt --type=json --patch '[{"op":"add","path":"/spec/configuration/network","value":{}},{"op":"add","path":"/spec/configuration/network/binding","value":{"l2bridge":{"domainAttachmentType":"managedTap","migration":{}}}}]'
391-
392-
if [ ! -d "./bin" ]
393-
then
394-
mkdir -p ./bin
395-
if_error_exit "Failed to create bin dir!"
396-
fi
397-
398-
if [[ "$OSTYPE" == "linux-gnu" ]]; then
399-
OS_TYPE="linux"
400-
elif [[ "$OSTYPE" == "darwin"* ]]; then
401-
OS_TYPE="darwin"
402-
fi
403-
404-
pushd ./bin
405-
if [ ! -f ./virtctl ]; then
406-
kubevirt_stable_release_url=$(get_kubevirt_release_url "stable")
407-
cli_name="virtctl-${kubevirt_stable_release_url##*/}-${OS_TYPE}-${ARCH}"
408-
curl -LO "${kubevirt_stable_release_url}/${cli_name}"
409-
mv ${cli_name} virtctl
410-
if_error_exit "Failed to download virtctl!"
411-
fi
412-
popd
413391

414-
chmod +x ./bin/virtctl
415392
}
416393

417394
install_cert_manager() {

test/e2e/infraprovider/api/api.go

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import (
44
"errors"
55
"fmt"
66
"strings"
7+
8+
"k8s.io/kubernetes/test/e2e/framework"
79
)
810

911
// Provider represents the infrastructure provider
@@ -37,6 +39,21 @@ type Provider interface {
3739
GetK8HostPort() uint16 // supported K8 host ports
3840
}
3941

42+
// Underlay represents the configuration for an underlay network.
43+
// Note: The physical network referenced by PhysicalNetworkName must be pre-created and available.
44+
type Underlay struct {
45+
// PhysicalNetworkName is the name of the pre-created physical network to use.
46+
PhysicalNetworkName string
47+
// LogicalNetworkName is the logical network name to be used.
48+
LogicalNetworkName string
49+
// BridgeName is the name of the bridge associated with the underlay.
50+
BridgeName string
51+
// PortName is the name of the port on the bridge.
52+
PortName string
53+
// VlanID is the VLAN identifier for the underlay network.
54+
VlanID int
55+
}
56+
4057
type Context interface {
4158
CreateExternalContainer(container ExternalContainer) (ExternalContainer, error)
4259
DeleteExternalContainer(container ExternalContainer) error
@@ -46,6 +63,7 @@ type Context interface {
4663
AttachNetwork(network Network, instance string) (NetworkInterface, error)
4764
DetachNetwork(network Network, instance string) error
4865
GetAttachedNetworks() (Networks, error)
66+
SetupUnderlay(f *framework.Framework, underlay Underlay) error
4967

5068
AddCleanUpFn(func() error)
5169
}
@@ -164,13 +182,14 @@ func (n NetworkInterface) GetMAC() string {
164182
}
165183

166184
type ExternalContainer struct {
167-
Name string
168-
Image string
169-
Network Network
170-
Args []string
171-
ExtPort uint16
172-
IPv4 string
173-
IPv6 string
185+
Name string
186+
Image string
187+
Network Network
188+
Entrypoint string
189+
Args []string
190+
ExtPort uint16
191+
IPv4 string
192+
IPv6 string
174193
}
175194

176195
func (ec ExternalContainer) GetName() string {

test/e2e/infraprovider/providers/kind/kind.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ import (
1313

1414
"github.com/onsi/ginkgo/v2"
1515
"github.com/ovn-org/ovn-kubernetes/test/e2e/containerengine"
16+
"github.com/ovn-org/ovn-kubernetes/test/e2e/deploymentconfig"
1617
"github.com/ovn-org/ovn-kubernetes/test/e2e/images"
1718
"github.com/ovn-org/ovn-kubernetes/test/e2e/infraprovider/api"
1819
"github.com/ovn-org/ovn-kubernetes/test/e2e/infraprovider/portalloc"
1920

21+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2022
"k8s.io/apimachinery/pkg/util/wait"
2123
"k8s.io/kubernetes/test/e2e/framework"
2224
utilnet "k8s.io/utils/net"
@@ -145,6 +147,9 @@ func (c *contextKind) createExternalContainer(container api.ExternalContainer) (
145147
return container, fmt.Errorf("container %s already exists", container.Name)
146148
}
147149
cmd := []string{"run", "-itd", "--privileged", "--name", container.Name, "--network", container.Network.Name(), "--hostname", container.Name}
150+
if container.Entrypoint != "" {
151+
cmd = append(cmd, "--entrypoint", container.Entrypoint)
152+
}
148153
cmd = append(cmd, container.Image)
149154
if len(container.Args) > 0 {
150155
cmd = append(cmd, container.Args...)
@@ -359,6 +364,83 @@ func (c *contextKind) getAttachedNetworks() (api.Networks, error) {
359364
return attachedNetworks, nil
360365
}
361366

367+
func (c *contextKind) SetupUnderlay(f *framework.Framework, underlay api.Underlay) error {
368+
if underlay.LogicalNetworkName == "" {
369+
return fmt.Errorf("underlay logical network name must be set")
370+
}
371+
372+
if underlay.PhysicalNetworkName == "" {
373+
underlay.PhysicalNetworkName = "underlay"
374+
}
375+
376+
if underlay.BridgeName == "" {
377+
underlay.BridgeName = secondaryBridge
378+
}
379+
380+
const (
381+
ovsKubeNodeLabel = "app=ovnkube-node"
382+
)
383+
384+
ovsPodList, err := f.ClientSet.CoreV1().Pods(deploymentconfig.Get().OVNKubernetesNamespace()).List(
385+
context.Background(),
386+
metav1.ListOptions{LabelSelector: ovsKubeNodeLabel},
387+
)
388+
if err != nil {
389+
return fmt.Errorf("failed to list OVS pods with label %q at namespace %q: %w", ovsKubeNodeLabel, deploymentconfig.Get().OVNKubernetesNamespace(), err)
390+
}
391+
392+
if len(ovsPodList.Items) == 0 {
393+
return fmt.Errorf("no pods with label %q in namespace %q", ovsKubeNodeLabel, deploymentconfig.Get().OVNKubernetesNamespace())
394+
}
395+
for _, ovsPod := range ovsPodList.Items {
396+
if underlay.BridgeName != deploymentconfig.Get().ExternalBridgeName() {
397+
underlayInterface, err := getNetworkInterface(ovsPod.Spec.NodeName, underlay.PhysicalNetworkName)
398+
if err != nil {
399+
return fmt.Errorf("failed to get underlay interface for network %s on node %s: %w", underlay.PhysicalNetworkName, ovsPod.Spec.NodeName, err)
400+
}
401+
c.AddCleanUpFn(func() error {
402+
if err := removeOVSBridge(ovsPod.Namespace, ovsPod.Name, underlay.BridgeName); err != nil {
403+
return fmt.Errorf("failed to remove OVS bridge %s for pod %s/%s during cleanup: %w", underlay.BridgeName, ovsPod.Namespace, ovsPod.Name, err)
404+
}
405+
return nil
406+
})
407+
if err := ensureOVSBridge(ovsPod.Namespace, ovsPod.Name, underlay.BridgeName); err != nil {
408+
return fmt.Errorf("failed to add OVS bridge %s for pod %s/%s: %w", underlay.BridgeName, ovsPod.Namespace, ovsPod.Name, err)
409+
}
410+
411+
if err := ovsAttachPortToBridge(ovsPod.Namespace, ovsPod.Name, underlay.BridgeName, underlayInterface.InfName); err != nil {
412+
return fmt.Errorf("failed to attach port %s to bridge %s for pod %s/%s: %w", underlayInterface.InfName, underlay.BridgeName, ovsPod.Namespace, ovsPod.Name, err)
413+
}
414+
if underlay.VlanID > 0 {
415+
if err := ovsEnableVLANAccessPort(ovsPod.Namespace, ovsPod.Name, underlay.BridgeName, underlayInterface.InfName, underlay.VlanID); err != nil {
416+
return fmt.Errorf("failed to enable VLAN %d on port %s for bridge %s for pod %s/%s: %w", underlay.VlanID, underlayInterface.InfName, underlay.BridgeName, ovsPod.Namespace, ovsPod.Name, err)
417+
}
418+
}
419+
}
420+
c.AddCleanUpFn(func() error {
421+
if err := configureBridgeMappings(
422+
ovsPod.Namespace,
423+
ovsPod.Name,
424+
defaultNetworkBridgeMapping(),
425+
); err != nil {
426+
return fmt.Errorf("failed to restore default bridge mappings for pod %s/%s during cleanup: %w", ovsPod.Namespace, ovsPod.Name, err)
427+
}
428+
return nil
429+
})
430+
431+
if err := configureBridgeMappings(
432+
ovsPod.Namespace,
433+
ovsPod.Name,
434+
defaultNetworkBridgeMapping(),
435+
bridgeMapping(underlay.LogicalNetworkName, underlay.BridgeName),
436+
); err != nil {
437+
return fmt.Errorf("failed to configure bridge mappings for pod %s/%s for logical network %s to bridge %s: %w", ovsPod.Namespace, ovsPod.Name, underlay.LogicalNetworkName, underlay.BridgeName, err)
438+
}
439+
}
440+
return nil
441+
442+
}
443+
362444
func (c *contextKind) AddCleanUpFn(cleanUpFn func() error) {
363445
c.Lock()
364446
defer c.Unlock()
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package kind
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
"time"
7+
8+
"github.com/ovn-org/ovn-kubernetes/test/e2e/deploymentconfig"
9+
10+
e2epodoutput "k8s.io/kubernetes/test/e2e/framework/pod/output"
11+
)
12+
13+
const (
14+
secondaryBridge = "ovsbr1"
15+
)
16+
17+
func ensureOVSBridge(podNamespace, podName string, bridgeName string) error {
18+
cmd := fmt.Sprintf("ovs-vsctl br-exists %[1]s || ovs-vsctl add-br %[1]s", bridgeName)
19+
if _, err := e2epodoutput.RunHostCmdWithRetries(podNamespace, podName, cmd, time.Second, time.Second*5); err != nil {
20+
return fmt.Errorf("failed to add ovs bridge %q: %v", bridgeName, err)
21+
}
22+
return nil
23+
}
24+
25+
func removeOVSBridge(podNamespace, podName string, bridgeName string) error {
26+
cmd := fmt.Sprintf("if ovs-vsctl br-exists %[1]s; then ovs-vsctl del-br %[1]s; fi", bridgeName)
27+
if _, err := e2epodoutput.RunHostCmdWithRetries(podNamespace, podName, cmd, time.Second, time.Second*5); err != nil {
28+
return fmt.Errorf("failed to remove ovs bridge %q: %v", bridgeName, err)
29+
}
30+
return nil
31+
}
32+
33+
func ovsAttachPortToBridge(podNamespace, podName string, bridgeName string, portName string) error {
34+
cmd := fmt.Sprintf("ovs-vsctl list port %[2]s || ovs-vsctl add-port %[1]s %[2]s", bridgeName, portName)
35+
if _, err := e2epodoutput.RunHostCmdWithRetries(podNamespace, podName, cmd, time.Second, time.Second*5); err != nil {
36+
return fmt.Errorf("failed to addadd port %s from OVS bridge %s: %v", portName, bridgeName, err)
37+
}
38+
return nil
39+
}
40+
41+
func ovsEnableVLANAccessPort(podNamespace, podName string, bridgeName string, portName string, vlanID int) error {
42+
cmd := fmt.Sprintf("ovs-vsctl set port %[1]s tag=%[2]d vlan_mode=access", portName, vlanID)
43+
if _, err := e2epodoutput.RunHostCmdWithRetries(podNamespace, podName, cmd, time.Second, time.Second*5); err != nil {
44+
return fmt.Errorf("failed to enable vlan access port %s from OVS bridge %s: %v", portName, bridgeName, err)
45+
}
46+
return nil
47+
}
48+
49+
type BridgeMapping struct {
50+
physnet string
51+
ovsBridge string
52+
}
53+
54+
func (bm BridgeMapping) String() string {
55+
return fmt.Sprintf("%s:%s", bm.physnet, bm.ovsBridge)
56+
}
57+
58+
type BridgeMappings []BridgeMapping
59+
60+
func (bms BridgeMappings) String() string {
61+
return strings.Join(Map(bms, func(bm BridgeMapping) string { return bm.String() }), ",")
62+
}
63+
64+
func Map[T, V any](items []T, fn func(T) V) []V {
65+
result := make([]V, len(items))
66+
for i, t := range items {
67+
result[i] = fn(t)
68+
}
69+
return result
70+
}
71+
72+
func configureBridgeMappings(podNamespace, podName string, mappings ...BridgeMapping) error {
73+
mappingsString := fmt.Sprintf("external_ids:ovn-bridge-mappings=%s", BridgeMappings(mappings).String())
74+
cmd := strings.Join([]string{"ovs-vsctl", "set", "open", ".", mappingsString}, " ")
75+
if _, err := e2epodoutput.RunHostCmdWithRetries(podNamespace, podName, cmd, time.Second, time.Second*5); err != nil {
76+
return fmt.Errorf("failed to configure bridge mappings %q: %v", mappingsString, err)
77+
}
78+
return nil
79+
}
80+
81+
func defaultNetworkBridgeMapping() BridgeMapping {
82+
return BridgeMapping{
83+
physnet: "physnet",
84+
ovsBridge: deploymentconfig.Get().ExternalBridgeName(),
85+
}
86+
}
87+
88+
func bridgeMapping(physnet, ovsBridge string) BridgeMapping {
89+
return BridgeMapping{
90+
physnet: physnet,
91+
ovsBridge: ovsBridge,
92+
}
93+
}

test/e2e/ipalloc/ipalloc.go

Lines changed: 0 additions & 47 deletions
This file was deleted.

0 commit comments

Comments
 (0)