Skip to content

Commit 61e57b1

Browse files
Sowmya viswamSowmya viswam
Sowmya viswam
authored and
Sowmya viswam
committed
Adding tests for limit on number of virtual clusters in a namespace
1 parent ece351f commit 61e57b1

File tree

6 files changed

+438
-3
lines changed

6 files changed

+438
-3
lines changed
+262
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
name: E2E Test Features CI
2+
3+
on:
4+
schedule:
5+
- cron: '* * * * *'
6+
workflow_dispatch:
7+
8+
env:
9+
REPOSITORY_NAME: ghcr.io/${{ github.repository }}-ci
10+
TAG_NAME: PR${{ github.event.number }}
11+
VCLUSTER_SUFFIX: vcluster
12+
VCLUSTER_NAME: vcluster
13+
VCLUSTER_NAMESPACE: vcluster
14+
15+
jobs:
16+
build-and-push-syncer-image:
17+
runs-on: ubuntu-latest
18+
steps:
19+
- name: Checkout repository
20+
uses: actions/checkout@v4
21+
with:
22+
fetch-depth: 0
23+
- run: git fetch --force --tags
24+
- name: Set up Go
25+
uses: actions/setup-go@v5
26+
with:
27+
go-version: "1.22"
28+
- name: Setup Just
29+
uses: extractions/setup-just@v2
30+
- name: Setup Syft
31+
uses: anchore/sbom-action/download-syft@v0.17.0
32+
- name: Setup GoReleaser
33+
uses: goreleaser/goreleaser-action@v6
34+
with:
35+
install-only: true
36+
version: latest
37+
- name: Build and save syncer image
38+
run: |
39+
set -x
40+
TELEMETRY_PRIVATE_KEY="" goreleaser build --single-target --snapshot --id vcluster --clean --output ./vcluster
41+
docker build -t "${{ env.REPOSITORY_NAME }}:${{ env.TAG_NAME }}" -f Dockerfile.release --build-arg TARGETARCH=amd64 --build-arg TARGETOS=linux .
42+
docker save -o vcluster_syncer "${{ env.REPOSITORY_NAME }}:${{ env.TAG_NAME }}"
43+
- name: Upload syncer image to artifact
44+
uses: actions/upload-artifact@v4
45+
with:
46+
name: vcluster_syncer
47+
path: ./vcluster_syncer
48+
retention-days: 7
49+
50+
build-vcluster-cli:
51+
runs-on: ubuntu-latest
52+
steps:
53+
- name: Checkout repository
54+
uses: actions/checkout@v4
55+
with:
56+
fetch-depth: 0
57+
- run: git fetch --force --tags
58+
- name: Set up Go
59+
uses: actions/setup-go@v5
60+
with:
61+
go-version: "1.22"
62+
- name: Setup Just
63+
uses: extractions/setup-just@v2
64+
- name: Setup Syft
65+
uses: anchore/sbom-action/download-syft@v0.17.0
66+
- name: Setup GoReleaser
67+
uses: goreleaser/goreleaser-action@v6
68+
with:
69+
install-only: true
70+
- name: Build vcluster cli
71+
run: |
72+
set -x
73+
TELEMETRY_PRIVATE_KEY="" goreleaser build --single-target --snapshot --id vcluster-cli --clean --output ./vcluster
74+
- name: Upload vcluster cli to artifact
75+
uses: actions/upload-artifact@v4
76+
with:
77+
name: vcluster
78+
path: ./vcluster
79+
retention-days: 7
80+
81+
build-tests:
82+
name: Build tests binaries
83+
runs-on: ubuntu-latest
84+
steps:
85+
- name: Checkout
86+
uses: actions/checkout@v4
87+
88+
- name: Configure git
89+
run: git config --global url.https://$GH_ACCESS_TOKEN@github.com/.insteadOf https://github.com/
90+
env:
91+
GH_ACCESS_TOKEN: ${{ secrets.GH_ACCESS_TOKEN }}
92+
93+
- name: Set up Go
94+
uses: actions/setup-go@v4
95+
with:
96+
go-version-file: go.mod
97+
98+
- name: Build e2e binary
99+
run: |
100+
cd ./test
101+
go run -mod=vendor github.com/onsi/ginkgo/v2/ginkgo build --require-suite -r --mod vendor $(ls -d ./features/* | jq -R . | jq -rcs '. | join(" \\\n")')
102+
env:
103+
GOWORK: off
104+
105+
- name: Upload test binaries to artifacts
106+
uses: actions/upload-artifact@v4
107+
with:
108+
name: test-binaries
109+
path: test/features/**/*.test
110+
retention-days: 7
111+
112+
generate-matrix:
113+
runs-on: ubuntu-latest
114+
steps:
115+
- name: Checkout code
116+
uses: actions/checkout@v4
117+
118+
- name: List Go files
119+
id: set-paths-matrix
120+
run: |
121+
cd ./test
122+
set -x
123+
sudo apt-get install -y jq
124+
125+
paths=$(ls -d ./features/*/)
126+
echo "matrix=$(printf '%s\n' "${paths}" | jq -R . | jq -cs .)" >> "$GITHUB_OUTPUT"
127+
128+
outputs:
129+
matrix: ${{ steps.set-paths-matrix.outputs.matrix }}
130+
131+
execute-feature-tests:
132+
needs:
133+
- build-and-push-syncer-image
134+
- build-vcluster-cli
135+
- build-tests
136+
- generate-matrix
137+
138+
runs-on: ubuntu-latest
139+
strategy:
140+
fail-fast: false
141+
matrix:
142+
test-suite-path: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
143+
steps:
144+
- name: Checkout repository
145+
uses: actions/checkout@v4
146+
147+
- uses: azure/setup-helm@v4
148+
name: Setup Helm
149+
with:
150+
version: "v3.11.0"
151+
152+
- name: Set up kind k8s cluster
153+
uses: engineerd/setup-kind@v0.5.0
154+
with:
155+
version: "v0.20.0"
156+
image: kindest/node:v1.30.0@sha256:047357ac0cfea04663786a612ba1eaba9702bef25227a794b52890dd8bcd692e
157+
158+
- name: Testing kind cluster set-up
159+
run: |
160+
set -x
161+
kubectl cluster-info
162+
kubectl get pods -n kube-system
163+
echo "kubectl config current-context:" $(kubectl config current-context)
164+
echo "KUBECONFIG env var:" ${KUBECONFIG}
165+
166+
- name: Download vcluster cli
167+
uses: actions/download-artifact@v4
168+
with:
169+
name: vcluster
170+
171+
- name: Download syncer image
172+
uses: actions/download-artifact@v4
173+
with:
174+
name: vcluster_syncer
175+
176+
- name: Download test binaries
177+
uses: actions/download-artifact@v4
178+
with:
179+
name: test-binaries
180+
path: ./test/features
181+
182+
- name: Create vcluster
183+
id: create-vcluster
184+
run: |
185+
set -x
186+
187+
kind load image-archive vcluster_syncer
188+
189+
chmod +x vcluster && sudo mv vcluster /usr/bin
190+
191+
cd ./test
192+
193+
sudo apt-get install -y sed
194+
195+
sed -i "s|REPLACE_REPOSITORY_NAME|${{ env.REPOSITORY_NAME }}|g" ${{ matrix.test-suite-path }}commonValues.yaml
196+
sed -i "s|REPLACE_TAG_NAME|${{ env.TAG_NAME }}|g" ${{ matrix.test-suite-path }}commonValues.yaml
197+
198+
vcluster create ${{ env.VCLUSTER_SUFFIX }} -n ${{ env.VCLUSTER_NAMESPACE }} \
199+
--create-namespace \
200+
--debug \
201+
--connect=false \
202+
--local-chart-dir ../chart \
203+
-f ${{ matrix.test-suite-path }}commonValues.yaml
204+
continue-on-error: true
205+
206+
- name: Wait until vcluster is ready
207+
id: wait-until-vcluster-is-ready
208+
if: steps.create-vcluster.outcome == 'success'
209+
run: |
210+
set -x
211+
212+
./hack/wait-for-pod.sh -l app=${{ env.VCLUSTER_SUFFIX }} -n ${{ env.VCLUSTER_NAMESPACE }}
213+
214+
continue-on-error: true
215+
216+
- name: Collect deployment information in case vcluster fails to start
217+
if: steps.wait-until-vcluster-is-ready.outcome != 'success'
218+
run: |
219+
set -x
220+
kubectl get pods -o yaml -n ${{ env.VCLUSTER_NAMESPACE }}
221+
echo "======================================================================================================================"
222+
kubectl get events -n ${{ env.VCLUSTER_NAMESPACE }} --sort-by='.lastTimestamp'
223+
echo "======================================================================================================================"
224+
kubectl logs -l app=${{ env.VCLUSTER_SUFFIX }} -n ${{ env.VCLUSTER_NAMESPACE }} -c syncer --tail=-1 -p || kubectl logs -l app=${{ env.VCLUSTER_SUFFIX }} -n ${{ env.VCLUSTER_NAMESPACE }} -c syncer --tail=-1
225+
echo "======================================================================================================================"
226+
kubectl describe pods -n ${{ env.VCLUSTER_NAMESPACE }}
227+
exit 1
228+
229+
# Skips NetworkPolicy tests because they require network plugin with support (e.g. Calico)
230+
- name: Execute tests
231+
id: execute-tests
232+
run: |
233+
set -x
234+
235+
cd ./test/features
236+
237+
cd $(echo "${{ matrix.test-suite-path }}" | sed -e 's#^./features/##' -e 's#/$##')
238+
239+
sudo chmod +x $(echo "${{ matrix.test-suite-path }}" | sed -e 's#^./features/##' -e 's#/$##').test
240+
241+
VCLUSTER_SUFFIX=${{ env.VCLUSTER_SUFFIX }} VCLUSTER_NAME=${{ env.VCLUSTER_NAME }} VCLUSTER_NAMESPACE=${{ env.VCLUSTER_NAMESPACE }} ./$(echo "${{ matrix.test-suite-path }}" | sed -e 's#^./features/##' -e 's#/$##').test -test.v --ginkgo.v --ginkgo.skip='.*NetworkPolicy.*' --ginkgo.fail-fast
242+
243+
if kubectl logs -l app=${{ env.VCLUSTER_SUFFIX }} -n ${{ env.VCLUSTER_NAMESPACE }} -c syncer --tail=-1 -p >/dev/null 2>/dev/null; then
244+
echo "vCluster has restarted during testing, failing..."
245+
exit 1
246+
fi
247+
248+
continue-on-error: true
249+
250+
- name: Print logs if tests fail
251+
if: steps.execute-tests.outcome == 'failure'
252+
run: |
253+
set -x
254+
kubectl get pods -o yaml -n ${{ env.VCLUSTER_NAMESPACE }}
255+
echo "======================================================================================================================"
256+
kubectl get events -n ${{ env.VCLUSTER_NAMESPACE }} --sort-by='.lastTimestamp'
257+
echo "======================================================================================================================"
258+
kubectl logs -l app=${{ env.VCLUSTER_SUFFIX }} -n ${{ env.VCLUSTER_NAMESPACE }} -c syncer --tail=-1 -p || kubectl logs -l app=${{ env.VCLUSTER_SUFFIX }} -n ${{ env.VCLUSTER_NAMESPACE }} -c syncer --tail=-1
259+
echo "======================================================================================================================"
260+
kubectl describe pods -n ${{ env.VCLUSTER_NAMESPACE }}
261+
exit 1
262+

test/deploy_changes/common/common_helpers.go

+25-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package common
22

33
import (
44
"bytes"
5+
"context"
6+
"fmt"
57
"os"
68
"os/exec"
79
"strings"
@@ -41,9 +43,13 @@ func DeployChangesToVClusterUsingCLI(f *framework.Framework) {
4143

4244
func DisconnectFromVCluster(f *framework.Framework) {
4345
disconnectCmd := exec.Command("vcluster", "disconnect")
44-
err := disconnectCmd.Run()
45-
if err != nil && !strings.Contains(err.Error(), "not a virtual cluster context") {
46-
framework.ExpectNoError(err, "Error disconnecting from vCluster")
46+
output, err := disconnectCmd.CombinedOutput()
47+
if err != nil {
48+
if strings.Contains(string(output), "is not a virtual cluster context") {
49+
fmt.Println("No virtual cluster context to disconnect from.")
50+
} else {
51+
framework.ExpectNoError(err, "Error disconnecting from vCluster")
52+
}
4753
}
4854
}
4955

@@ -55,3 +61,19 @@ func VerifyClusterIsActive(f *framework.Framework) {
5561
return err == nil && strings.Contains(string(output), f.VclusterName) && strings.Contains(string(output), "Running")
5662
}).WithPolling(pollingInterval).WithTimeout(pollingDurationLong).Should(gomega.BeTrue())
5763
}
64+
65+
func DeleteVCluster(vClusterName string, f *framework.Framework) {
66+
ctx, cancel := context.WithTimeout(context.Background(), pollingDurationLong)
67+
defer cancel()
68+
69+
deleteCmd := exec.CommandContext(ctx, "vcluster", "delete", vClusterName, "-n", f.VclusterNamespace)
70+
var stdout, stderr bytes.Buffer
71+
deleteCmd.Stdout = &stdout
72+
deleteCmd.Stderr = &stderr
73+
err := deleteCmd.Run()
74+
if err != nil {
75+
fmt.Println("stderr: ", stderr.String())
76+
framework.ExpectNoError(err, "Error executing vcluster delete command")
77+
}
78+
gomega.Expect(strings.Contains(stdout.String(), "Successfully deleted virtual cluster")).To(gomega.BeTrue())
79+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
controlPlane:
2+
backingStore:
3+
etcd:
4+
deploy:
5+
statefulSet:
6+
resources:
7+
requests:
8+
cpu: "0"
9+
statefulSet:
10+
image:
11+
registry: ""
12+
repository: REPLACE_REPOSITORY_NAME
13+
tag: REPLACE_TAG_NAME
14+
env:
15+
- name: DEBUG
16+
value: "true"
17+
resources:
18+
requests:
19+
cpu: "0"
20+
# values for general test suite
21+
networking:
22+
replicateServices:
23+
toHost:
24+
- from: test/test
25+
to: test
26+
- from: test/nginx
27+
to: nginx
28+
fromHost:
29+
- from: test/test
30+
to: default/test
31+
- from: test/nginx
32+
to: default/nginx
33+
experimental:
34+
syncSettings:
35+
setOwner: true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package testfeatures
2+
3+
import (
4+
"bytes"
5+
"os/exec"
6+
"strings"
7+
8+
"github.com/loft-sh/vcluster/test/framework"
9+
"github.com/onsi/gomega"
10+
)
11+
12+
func noDuplicateVirtualClusterInSameNamespace(vClusterName string, f *framework.Framework) {
13+
deployCmd := exec.Command("vcluster", "create", vClusterName, "--namespace", f.VclusterNamespace, "-f", filePath)
14+
output, err := deployCmd.CombinedOutput()
15+
framework.ExpectError(err)
16+
gomega.Expect(strings.Contains(string(output), "there is already a virtual cluster in namespace")).To(gomega.BeTrue())
17+
}
18+
19+
func deploySecondVClusterInSameNamespace(vClusterName string, f *framework.Framework) {
20+
gomega.Eventually(func() bool {
21+
stdout := &bytes.Buffer{}
22+
deployCmd := exec.Command("vcluster", "create", vClusterName, "--namespace", f.VclusterNamespace, "-f", filePath, "--reuse-namespace")
23+
deployCmd.Stdout = stdout
24+
err := deployCmd.Run()
25+
framework.ExpectNoError(err)
26+
return err == nil && strings.Contains(stdout.String(), "Switched active kube context to")
27+
}).WithPolling(pollingInterval).WithTimeout(pollingDurationLong).Should(gomega.BeTrue())
28+
}

0 commit comments

Comments
 (0)