Skip to content

Commit

Permalink
Merge branch 'kubeovn:master' into bugfix
Browse files Browse the repository at this point in the history
  • Loading branch information
hackerain authored Nov 11, 2024
2 parents 54ed9a2 + f50da53 commit 258cc34
Show file tree
Hide file tree
Showing 7 changed files with 249 additions and 43 deletions.
118 changes: 115 additions & 3 deletions .github/workflows/build-x86-image.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ concurrency:
cancel-in-progress: true

env:
KIND_VERSION: v0.24.0
GOLANGCI_LINT_VERSION: 'v1.61.0'
KIND_VERSION: v0.25.0
GOLANGCI_LINT_VERSION: 'v1.62.0'
HELM_VERSION: v3.16.2
SUBMARINER_VERSION: '0.18.1'
SUBMARINER_VERSION: '0.18.2'

jobs:
build-kube-ovn-base:
Expand Down Expand Up @@ -2844,6 +2844,118 @@ jobs:
if: ${{ success() || (failure() && (steps.install.conclusion == 'failure' || steps.kube-ovn-ipsec-e2e.conclusion == 'failure')) }}
run: make check-kube-ovn-pod-restarts

kube-ovn-connectivity-test:
name: Kube-OVN Connectivity E2E
needs:
- build-kube-ovn
- build-e2e-binaries
runs-on: ubuntu-24.04
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
mode:
- overlay
- underlay
steps:
- uses: jlumbroso/[email protected]
with:
android: true
dotnet: true
haskell: true
docker-images: false
large-packages: false
tool-cache: false
swap-storage: false

- uses: actions/checkout@v4

- name: Create the default branch directory
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
run: mkdir -p test/e2e/source

- name: Check out the default branch
if: (github.base_ref || github.ref_name) != github.event.repository.default_branch
uses: actions/checkout@v4
with:
ref: ${{ github.event.repository.default_branch }}
fetch-depth: 1
path: test/e2e/source

- name: Export E2E directory
run: |
if [ '${{ github.base_ref || github.ref_name }}' = '${{ github.event.repository.default_branch }}' ]; then
echo "E2E_DIR=." >> "$GITHUB_ENV"
else
echo "E2E_DIR=test/e2e/source" >> "$GITHUB_ENV"
fi
- uses: actions/setup-go@v5
id: setup-go
with:
go-version-file: ${{ env.E2E_DIR }}/go.mod
check-latest: true
cache: false

- name: Export Go full version
run: echo "GO_VERSION=${{ steps.setup-go.outputs.go-version }}" >> "$GITHUB_ENV"

- name: Go cache
uses: actions/cache/restore@v4
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-${{ hashFiles(format('{0}/**/go.sum', env.E2E_DIR)) }}
restore-keys: ${{ runner.os }}-e2e-go-${{ env.GO_VERSION }}-x86-

- name: Install kind
uses: helm/[email protected]
with:
version: ${{ env.KIND_VERSION }}
install_only: true

- name: Install ginkgo
working-directory: ${{ env.E2E_DIR }}
run: go install -v -mod=mod github.com/onsi/ginkgo/v2/ginkgo

- name: Download kube-ovn image
uses: actions/download-artifact@v4
with:
name: kube-ovn

- name: Load images
run: docker load -i kube-ovn.tar

- name: Create kind cluster
run: |
pipx install jinjanator
make kind-init
- name: Install Kube-OVN
id: install
run: make kind-install-${{ matrix.mode }}

- name: Run E2E
id: e2e
working-directory: ${{ env.E2E_DIR }}
env:
E2E_BRANCH: ${{ github.base_ref || github.ref_name }}
run: make kube-ovn-connectivity-e2e

- name: kubectl ko log
if: failure() && (steps.e2e.conclusion == 'failure')
run: |
make kubectl-ko-log
mv kubectl-ko-log.tar.gz kube-ovn-connectivity-e2e-${{ matrix.mode }}-ko-log.tar.gz
- name: upload kubectl ko log
uses: actions/upload-artifact@v4
if: failure() && (steps.kube-ovn-connectivity-e2e.conclusion == 'failure')
with:
name: kube-ovn-connectivity-e2e-${{ matrix.mode }}-ko-log
path: kube-ovn-connectivity-e2e-${{ matrix.mode }}-ko-log.tar.gz

push:
name: Push Images
needs:
Expand Down
9 changes: 6 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ CONTROL_PLANE_TAINTS = node-role.kubernetes.io/master node-role.kubernetes.io/co
FRR_VERSION = 9.1.2
FRR_IMAGE = quay.io/frrouting/frr:$(FRR_VERSION)

CLAB_IMAGE = ghcr.io/srl-labs/clab:0.58.0
CLAB_IMAGE = ghcr.io/srl-labs/clab:0.59.0

MULTUS_VERSION = v4.1.3
MULTUS_IMAGE = ghcr.io/k8snetworkplumbingwg/multus-cni:$(MULTUS_VERSION)-thick
Expand Down Expand Up @@ -59,7 +59,7 @@ CERT_MANAGER_CAINJECTOR = quay.io/jetstack/cert-manager-cainjector:$(CERT_MANAGE
CERT_MANAGER_WEBHOOK = quay.io/jetstack/cert-manager-webhook:$(CERT_MANAGER_VERSION)
CERT_MANAGER_YAML = https://github.com/cert-manager/cert-manager/releases/download/$(CERT_MANAGER_VERSION)/cert-manager.yaml

SUBMARINER_VERSION = $(shell echo $${SUBMARINER_VERSION:-0.18.1})
SUBMARINER_VERSION = $(shell echo $${SUBMARINER_VERSION:-0.18.2})
SUBMARINER_OPERATOR = quay.io/submariner/submariner-operator:$(SUBMARINER_VERSION)
SUBMARINER_GATEWAY = quay.io/submariner/submariner-gateway:$(SUBMARINER_VERSION)
SUBMARINER_LIGHTHOUSE_AGENT = quay.io/submariner/lighthouse-agent:$(SUBMARINER_VERSION)
Expand All @@ -78,7 +78,7 @@ DEEPFLOW_GRAFANA_NODE_PORT = 30080
DEEPFLOW_MAPPED_PORTS = $(DEEPFLOW_SERVER_NODE_PORT),$(DEEPFLOW_SERVER_GRPC_PORT),$(DEEPFLOW_SERVER_HTTP_PORT),$(DEEPFLOW_GRAFANA_NODE_PORT)
DEEPFLOW_CTL_URL = https://deepflow-ce.oss-cn-beijing.aliyuncs.com/bin/ctl/$(DEEPFLOW_VERSION)/linux/$(shell arch | sed 's|x86_64|amd64|' | sed 's|aarch64|arm64|')/deepflow-ctl

KWOK_VERSION = v0.6.0
KWOK_VERSION = v0.6.1
KWOK_IMAGE = registry.k8s.io/kwok/kwok:$(KWOK_VERSION)

VPC_NAT_GW_IMG = $(REGISTRY)/vpc-nat-gateway:$(VERSION)
Expand Down Expand Up @@ -559,6 +559,9 @@ kind-install-ipv6:
kind-install-dual:
@DUAL_STACK=true $(MAKE) kind-install

.PHONY: kind-install-overlay
kind-install-overlay: kind-install-overlay-ipv4

.PHONY: kind-install-overlay-%
kind-install-overlay-%:
@$(MAKE) kind-install-$*
Expand Down
24 changes: 12 additions & 12 deletions dist/images/Dockerfile.base
Original file line number Diff line number Diff line change
Expand Up @@ -37,29 +37,29 @@ RUN cd /usr/src/ && \
RUN cd /usr/src/ && git clone -b branch-24.03 --depth=1 https://github.com/ovn-org/ovn.git && \
cd ovn && \
# change hash type from dp_hash to hash with field src_ip
curl -s https://github.com/kubeovn/ovn/commit/4b2d0bffda64fcfca876fe62a02486d7927c1162.patch | git apply && \
curl -s https://github.com/kubeovn/ovn/commit/61ece99b63e88bb12c030c34b46716b01e242c92.patch | git apply && \
# modify src route priority
curl -s https://github.com/kubeovn/ovn/commit/3dbceb75c5e23d8d5b555e5d87238d40cb557424.patch | git apply && \
curl -s https://github.com/kubeovn/ovn/commit/cecf1515de299b3ec6b30ed8a167748e879188a6.patch | git apply && \
# fix reaching resubmit limit in underlay
curl -s https://github.com/kubeovn/ovn/commit/37d093c99c4980696cf917a1ad47492881908c90.patch | git apply && \
curl -s https://github.com/kubeovn/ovn/commit/eb935585bdeecdaa3fba8ff2c46ef394ce8d2424.patch | git apply && \
# ovn-controller: do not send GARP on localnet for Kube-OVN ports
curl -s https://github.com/kubeovn/ovn/commit/35efb84d45d2598fc83fabaee8100987dcbc6795.patch | git apply && \
curl -s https://github.com/kubeovn/ovn/commit/8236ec78aedd114b3ce22158a9e0282337787259.patch | git apply && \
# northd: add nb option version_compatibility
curl -s https://github.com/kubeovn/ovn/commit/ef92cdbc10ee247ea7db7803e86e1d51c9cdaddf.patch | git apply && \
curl -s https://github.com/kubeovn/ovn/commit/19bdf15ec5542005e3a1ef073dfe688c023d144c.patch | git apply && \
# add support for conditionally skipping conntrack
curl -s https://github.com/kubeovn/ovn/commit/41b419e54ef5671214eb3b5dfb53301152ce6dd1.patch | git apply && \
curl -s https://github.com/kubeovn/ovn/commit/c6ea5e214a4a20eccdf8cd18c232284edc5ce951.patch | git apply && \
# northd: skip conntrack when access node local dns ip
curl -s https://github.com/kubeovn/ovn/commit/b01a339c3b56eff45b22d414ed9d6e4a37527cd5.patch | git apply && \
curl -s https://github.com/kubeovn/ovn/commit/d8ce6dc8e512b703903c53e344b1dce1a0c61d2e.patch | git apply && \
# lflow: do not send direct traffic between lports to conntrack
curl -s https://github.com/kubeovn/ovn/commit/5687a692ef4c10c6ec9bfeca7b920e7736a4016c.patch | git apply && \
curl -s https://github.com/kubeovn/ovn/commit/baf2d74f0f2d746c01c22002ea72426d75cfc79a.patch | git apply && \
# set ether dst addr for dnat on logical switch
curl -s https://github.com/kubeovn/ovn/commit/08cfd7a4c56c610d6bf7dcf8be016f5ac7928f28.patch | git apply && \
curl -s https://github.com/kubeovn/ovn/commit/63762db7a4c37185f4c87962c50b414d925b5d33.patch | git apply && \
# fix lr-lb dnat with multiple distributed gateway ports
curl -s https://github.com/kubeovn/ovn/commit/d326dd12b2ecc3b65f7360aac8e7c35c4bed2026.patch | git apply && \
curl -s https://github.com/kubeovn/ovn/commit/ca5ccf3c8ac67bcc005110c8c62214d2684e7e41.patch | git apply && \
# northd: skip arp/nd request for lrp addresses from localnet ports
curl -s https://github.com/kubeovn/ovn/commit/cf6ba220851ae13de76473b6569097bb70ec76d8.patch | git apply && \
curl -s https://github.com/kubeovn/ovn/commit/283930b627ffa843ebf0e7c3fa0cc70edacfdd12.patch | git apply && \
# ovn-controller: make activation strategy work for single chassis
curl -s https://github.com/kubeovn/ovn/commit/487cd1c6c0cc9def7cedaaaf3dd4bc99c23974c4.patch | git apply
curl -s https://github.com/kubeovn/ovn/commit/1160d956e49e8f3f1b19535dbf1b9a624a090717.patch | git apply

RUN apt install -y build-essential fakeroot \
autoconf automake bzip2 debhelper-compat dh-exec dh-python dh-sequence-python3 dh-sequence-sphinxdoc \
Expand Down
113 changes: 108 additions & 5 deletions test/e2e/connectivity/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func TestE2E(t *testing.T) {

type suiteContext struct {
Node string
HostIP string
NodeIP string
NodePort int32
}

Expand Down Expand Up @@ -108,9 +108,28 @@ var _ = ginkgo.SynchronizedBeforeSuite(func() []byte {
framework.ExpectNoError(err)
framework.ExpectNotNil(pods)
framework.ExpectNotEmpty(pods.Items, "no pod found in deployment "+deploymentName)
suiteCtx.HostIP = pods.Items[0].Status.HostIP
suiteCtx.NodeIP = pods.Items[0].Status.HostIP
suiteCtx.Node = pods.Items[0].Spec.NodeName

ginkgo.By("Getting all nodes")
nodes, err := cs.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{})
framework.ExpectNoError(err)
framework.ExpectNotNil(nodes)
framework.ExpectNotEmpty(nodes.Items)

// use the internal IP of the node that is not the same as the pod node
for _, node := range nodes.Items {
if node.Name != suiteCtx.Node {
ipv4, ipv6 := util.GetNodeInternalIP(node)
if ipv4 != "" {
suiteCtx.NodeIP = ipv4
} else {
suiteCtx.NodeIP = ipv6
}
break
}
}

ginkgo.By("Creating service " + serviceName)
ports := []corev1.ServicePort{{
Name: "tcp",
Expand Down Expand Up @@ -157,13 +176,13 @@ var _ = framework.Describe("[group:connectivity]", func() {
})
ginkgo.AfterEach(ginkgo.OncePerOrdered, func() {
ginkgo.By("Closing RPC server")
framework.ExpectNoError(server.Close())
framework.ExpectNoError(server.Shutdown(context.Background()))
})

ginkgo.It("Continuous NodePort HTTP testing", func() {
u := url.URL{
Scheme: "http",
Host: util.JoinHostPort(suiteCtx.HostIP, suiteCtx.NodePort),
Host: util.JoinHostPort(suiteCtx.NodeIP, suiteCtx.NodePort),
Path: "/clientip",
}
ginkgo.By("GET " + u.String())
Expand Down Expand Up @@ -263,7 +282,7 @@ var _ = framework.OrderedDescribe("[group:disaster]", func() {
framework.ExpectNotEmpty(pods.Items, "no pod found in deployment ovn-central")

for _, pod := range pods.Items {
framework.Logf("pod %s is running on %s", pod.Name, pod.Spec.NodeName)
ginkgo.By("Deleting pod " + pod.Name + " running on " + pod.Spec.NodeName)
err = cs.CoreV1().Pods(pod.Namespace).Delete(context.TODO(), pod.Name, metav1.DeleteOptions{})
framework.ExpectNoError(err, "failed to delete pod "+pod.Name)
}
Expand All @@ -281,6 +300,90 @@ var _ = framework.OrderedDescribe("[group:disaster]", func() {
}
})

framework.DisruptiveIt("Stop ovn sb process", func() {
ginkgo.By("Getting deployment ovn-central")
deploymentClient := framework.NewDeploymentClient(cs, framework.KubeOvnNamespace)
deploy := deploymentClient.Get("ovn-central")

ginkgo.By("Getting pods of deployment ovn-central")
pods, err := deploymentClient.GetPods(deploy)
framework.ExpectNoError(err)
framework.ExpectNotEmpty(pods.Items, "no pod found in deployment ovn-central")

for _, pod := range pods.Items {
ginkgo.By("Getting ovn sb pid of pod " + pod.Name + " running on " + pod.Spec.NodeName)
cmd := []string{"cat", "/run/ovn/ovnsb_db.pid"}
stdout, stderr, err := framework.KubectlExec(pod.Namespace, pod.Name, cmd...)
framework.ExpectNoError(err, "failed to get ovn sb pid: %v, %s", err, string(stderr))
pid := string(bytes.TrimSpace(stdout))
framework.Logf("ovn sb pid: %s", pid)

ginkgo.By("Stopping ovn sb process by sending a STOP signal")
cmd = []string{"sh", "-c", fmt.Sprintf(`"kill -STOP %s"`, pid)}
_, stderr, err = framework.KubectlExec(pod.Namespace, pod.Name, cmd...)
framework.ExpectNoError(err, "failed to send STOP signal to ovn sb process: %v, %s", err, string(stderr))
}

ginkgo.By("Waiting 60s")
time.Sleep(60 * time.Second)

for _, pod := range pods.Items {
ginkgo.By("Getting ovn sb pid of pod " + pod.Name + " running on " + pod.Spec.NodeName)
cmd := []string{"cat", "/run/ovn/ovnsb_db.pid"}
stdout, stderr, err := framework.KubectlExec(pod.Namespace, pod.Name, cmd...)
framework.ExpectNoError(err, "failed to get ovn sb pid: %v, %s", err, string(stderr))
pid := string(bytes.TrimSpace(stdout))
framework.Logf("ovn sb pid: %s", pid)

ginkgo.By("Stopping ovn sb process by sending a CONT signal")
cmd = []string{"sh", "-c", fmt.Sprintf(`"kill -CONT %s"`, pid)}
_, stderr, err = framework.KubectlExec(pod.Namespace, pod.Name, cmd...)
framework.ExpectNoError(err, "failed to send CONT signal to ovn sb process: %v, %s", err, string(stderr))
}
})

framework.DisruptiveIt("Stop ovn-controller process", func() {
ginkgo.By("Getting DaemonSet ovs-ovn")
dsClient := framework.NewDaemonSetClient(cs, framework.KubeOvnNamespace)
ds := dsClient.Get("ovs-ovn")

ginkgo.By("Getting pods of DaemonSet ovs-ovn")
pods, err := dsClient.GetPods(ds)
framework.ExpectNoError(err)
framework.ExpectNotEmpty(pods.Items, "no pod found in DaemonSet ovs-ovn")

ginkgo.By("Getting ovs-ovn pod running on node " + suiteCtx.Node)
var pod *corev1.Pod
for i := range pods.Items {
framework.Logf("pod %s is running on %s", pods.Items[i].Name, pods.Items[i].Spec.NodeName)
if pods.Items[i].Spec.NodeName == suiteCtx.Node {
pod = &pods.Items[i]
break
}
}
framework.ExpectNotNil(pod, "no ovs-ovn pod running on node "+suiteCtx.Node)

ginkgo.By("Getting ovn-controller pid")
cmd := []string{"sh", "-c", `"pidof -s ovn-controller"`}
stdout, stderr, err := framework.KubectlExec(pod.Namespace, pod.Name, cmd...)
framework.ExpectNoError(err, "failed to get ovn-controller pid: %v, %s", err, string(stderr))
pid := string(bytes.TrimSpace(stdout))
framework.Logf("ovn-controller pid: %s", pid)

ginkgo.By("Stopping ovn-controller process by sending a STOP signal")
cmd = []string{"sh", "-c", fmt.Sprintf(`"kill -STOP %s"`, pid)}
_, stderr, err = framework.KubectlExec(pod.Namespace, pod.Name, cmd...)
framework.ExpectNoError(err, "failed to send STOP signal to ovn-controller process: %v, %s", err, string(stderr))

ginkgo.By("Waiting 60s")
time.Sleep(60 * time.Second)

ginkgo.By("Continuing the stopped ovn-controller process by sending a CONT signal")
cmd = []string{"sh", "-c", fmt.Sprintf(`"kill -CONT %s"`, pid)}
_, stderr, err = framework.KubectlExec(pod.Namespace, pod.Name, cmd...)
framework.ExpectNoError(err, "failed to send CONT signal to ovn-controller process: %v, %s", err, string(stderr))
})

framework.DisruptiveIt("Stop ovs-vswitchd process", func() {
ginkgo.By("Getting DaemonSet ovs-ovn")
dsClient := framework.NewDaemonSetClient(cs, framework.KubeOvnNamespace)
Expand Down
Loading

0 comments on commit 258cc34

Please sign in to comment.