diff --git a/.semaphore/end-to-end/pipelines/windows.yml b/.semaphore/end-to-end/pipelines/windows.yml index 1685f7e1ab8..955c397aacb 100644 --- a/.semaphore/end-to-end/pipelines/windows.yml +++ b/.semaphore/end-to-end/pipelines/windows.yml @@ -4,7 +4,7 @@ name: banzai-calico Windows agent: machine: - type: c1-standard-1 + type: f1-standard-2 os_image: ubuntu2204 execution_time_limit: @@ -24,88 +24,88 @@ global_job_config: - name: CREATE_WINDOWS_NODES value: "true" - name: K8S_E2E_FLAGS - value: --ginkgo.focus=\[sig-calico\].*\[RunsOnWindows\] + value: --ginkgo.focus=(\[sig-calico\].*\[RunsOnWindows\]) --ginkgo.skip=(\[LinuxOnly\]) - name: FUNCTIONAL_AREA value: "windows.yml" - name: USE_PRIVATE_REGISTRY value: "true" - name: PRIVATE_REGISTRY value: "quay.io/" + - name: INSTALLER + value: "operator" + - name: RUN_LOCAL_TESTS # run e2e tests from locally built binary + value: "true" # Dimensions -# Provisioners: aws-kubeadm, gcp-kubeadm, rancher +# Provisioners: azr-aso, azr-aks # Installer: operator -# Windows OS: Windows Server 1809, Windows Server 2022 +# Windows OS: Windows Server 2022 # k8s Versions: stable-3, stable-1, stable # linux dataplane: bpf, iptables, nftables -# encapsulation: vxlan, none +# encapsulation: vxlan # Runs: -# aws-kubeadm, 1809, stable-3, iptables, none -# gcp-kubeadm, 2022, stable, bpf, vxlan -# gcp-rancher, 2022, stable-1, nftables, none +# azr-aso, 2022, stable, bpf, vxlan +# azr-aso, 2022, stable-1, nftables, vxlan +# azr-aks, 2022, stable-1, iptables, no-encap, azure CNI blocks: - name: Calico Windows dependencies: [] task: jobs: - - name: aws-kubeadm, 1809, stable-3, iptables, none + - name: "azr-aso, 2022, stable, bpf, vxlan" execution_time_limit: hours: 5 commands: - ~/calico/.semaphore/end-to-end/scripts/body_standard.sh env_vars: - name: PROVISIONER - value: aws-kubeadm - - name: WINDOWS_OS_VERSION - value: "1809" + value: azr-aso - name: K8S_VERSION - value: stable-3 + value: stable-1 - name: DATAPLANE - value: CalicoIptables + value: CalicoBPF - name: ENCAPSULATION_TYPE - value: None - - name: VPC_SUBNETS - value: '["172.16.101.0/24"]' # single subnet because no encapsulation is being used + value: VXLAN + - name: WINDOWS_OS + value: "2022" - - name: gcp-kubeadm, 2022, stable, bpf, vxlan + - name: "azr-aso, 2022, stable-1, nftables, vxlan" execution_time_limit: hours: 5 commands: - ~/calico/.semaphore/end-to-end/scripts/body_standard.sh env_vars: - name: PROVISIONER - value: gcp-kubeadm - - name: WINDOWS_OS_VERSION - value: "2022" + value: azr-aso - name: K8S_VERSION - value: stable + value: stable-1 - name: DATAPLANE - value: CalicoBPF + value: CalicoNftables - name: ENCAPSULATION_TYPE value: VXLAN + - name: WINDOWS_OS + value: "2022" - - name: gcp-rancher, 2022, stable-1, nftables, vxlan + - name: "azr-aks, 2022, stable-1, iptables, no encap, azure CNI" execution_time_limit: hours: 5 commands: - ~/calico/.semaphore/end-to-end/scripts/body_standard.sh env_vars: - name: PROVISIONER - value: gcp-rancher - - name: WINDOWS_OS_VERSION - value: "2022" + value: azr-aks - name: K8S_VERSION value: stable-1 - name: DATAPLANE - value: CalicoNftables + value: CalicoIptables - name: ENCAPSULATION_TYPE - value: VXLAN - - name: RKE_VERSION # Don't just update these versions, need k8s and rke versions to match. - value: "v1.8.6" # https://github.com/rancher/rke/releases/tag/v1.8.6 - - name: K8S_VERSION - value: "v1.32.7" # RKE 1.8.6 supports: v1.30.14-rancher1-1, v1.31.11-rancher1-1, v1.32.7-rancher1-1 + value: "None" + - name: WINDOWS_OS + value: "2022" + - name: USE_VENDORED_CNI + value: "true" promotions: - name: Cleanup jobs diff --git a/.semaphore/end-to-end/scripts/body_standard.sh b/.semaphore/end-to-end/scripts/body_standard.sh index 2fc8e09f0c7..eb73d1ded3f 100755 --- a/.semaphore/end-to-end/scripts/body_standard.sh +++ b/.semaphore/end-to-end/scripts/body_standard.sh @@ -84,12 +84,20 @@ else echo "[INFO] starting bz upgrade..." bz upgrade $VERBOSE | tee >(gzip --stdout > ${BZ_LOGS_DIR}/upgrade.log.gz) fi - + if [[ ${MCM_STAGE:-} != *-mgmt* ]] && [[ ${HCP_STAGE:-} != *-hosting* ]]; then echo "[INFO] Test logs will be available here after the run: ${SEMAPHORE_ORGANIZATION_URL}/artifacts/jobs/${SEMAPHORE_JOB_ID}?path=semaphore%2Flogs" echo "[INFO] Alternatively, you can view logs while job is running using 'sem attach ${SEMAPHORE_JOB_ID}' and then 'tail -f ${BZ_LOGS_DIR}/${TEST_TYPE}-tests.log'" - echo "[INFO] starting bz testing..." - bz tests $VERBOSE |& tee >(gzip --stdout > ${BZ_LOGS_DIR}/${TEST_TYPE}-tests.log.gz) + if [[ -n "$RUN_LOCAL_TESTS" ]]; then + echo "[INFO] starting e2e testing from local binary..." + pushd ${HOME}/calico + make -C e2e build |& tee >(gzip --stdout > ${BZ_LOGS_DIR}/${TEST_TYPE}-tests.log.gz) + KUBECONFIG=${BZ_LOCAL_DIR}/kubeconfig PRODUCT=calico ./e2e/bin/k8s/e2e.test ${K8S_E2E_FLAGS} |& tee -a >(gzip --stdout > ${BZ_LOGS_DIR}/${TEST_TYPE}-tests.log.gz) + popd + else + echo "[INFO] starting bz testing..." + bz tests $VERBOSE |& tee >(gzip --stdout > ${BZ_LOGS_DIR}/${TEST_TYPE}-tests.log.gz) + fi fi fi diff --git a/.semaphore/end-to-end/scripts/global_prologue.sh b/.semaphore/end-to-end/scripts/global_prologue.sh index 456fbaa78c0..7b07154159a 100755 --- a/.semaphore/end-to-end/scripts/global_prologue.sh +++ b/.semaphore/end-to-end/scripts/global_prologue.sh @@ -125,6 +125,12 @@ gcloud auth activate-service-account --key-file="${GOOGLE_APPLICATION_CREDENTIAL gcloud config set project ${GOOGLE_PROJECT} export GOOGLE_ZONE=${GOOGLE_ZONE:-$(gcloud compute zones list --filter="region~'$GOOGLE_REGION'" --format="value(name)" | awk 'BEGIN {srand()} {a[NR]=$0} rand() * NR < 1 {zone=$0} END {print zone}')} +dummy_needrestart_cmd="echo \"[INFO] creating dummy needrestart script in /usr/local/bin\"" +dummy_needrestart_cmd="$dummy_needrestart_cmd; echo \#\!/usr/bin/bash | sudo tee /usr/local/bin/needrestart" +dummy_needrestart_cmd="$dummy_needrestart_cmd && echo 'echo [DEBUG] dummy needrestart invoked' | sudo tee -a /usr/local/bin/needrestart" +dummy_needrestart_cmd="$dummy_needrestart_cmd && sudo chmod +x /usr/local/bin/needrestart" +if ! command -v needrestart; then eval "$dummy_needrestart_cmd"; fi + # Update package lists to ensure the latest versions are available. # Temporarily disable needrestart during installation to avoid interactive prompts. # Set needrestart to automatically restart all required services after installation. diff --git a/e2e/pkg/tests/policy/policy.go b/e2e/pkg/tests/policy/policy.go index 0626fe10b05..6b7084bce3c 100644 --- a/e2e/pkg/tests/policy/policy.go +++ b/e2e/pkg/tests/policy/policy.go @@ -41,6 +41,7 @@ var _ = describe.CalicoDescribe( describe.WithTeam(describe.Core), describe.WithFeature("NetworkPolicy"), describe.WithCategory(describe.Policy), + describe.WithWindows(), "Calico NetworkPolicy", func() { // Define variables common across all tests. @@ -93,11 +94,11 @@ var _ = describe.CalicoDescribe( // - Creating a default-deny policy applied to both namespaces using a GlobalNetworkPolicy. // - Isolating both namespaces with ingress and egress policies // - Asserting only same namespace connectivity exists. - framework.ConformanceIt("should correctly isolate namespaces [RunsOnWindows]", func() { + framework.ConformanceIt("should correctly isolate namespaces", func() { nsA := f.Namespace By("Creating a second namespace B") - ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second) defer cancel() nsB, err := f.CreateNamespace(ctx, f.BaseName+"-b", nil) Expect(err).NotTo(HaveOccurred()) @@ -286,7 +287,8 @@ var _ = describe.CalicoDescribe( framework.ConformanceIt("should support namespace selectors", func() { ns := f.Namespace - ctx := context.Background() + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() By(fmt.Sprintf("Applying a default-deny policy to namespace %s", ns.Name)) defaultDeny := newDefaultDenyIngressPolicy(ns.Name) diff --git a/e2e/pkg/utils/conncheck/conncheck.go b/e2e/pkg/utils/conncheck/conncheck.go index 258f57b53dc..8cfa8019aeb 100644 --- a/e2e/pkg/utils/conncheck/conncheck.go +++ b/e2e/pkg/utils/conncheck/conncheck.go @@ -141,10 +141,14 @@ func (c *connectionTester) deploy() error { // Wait for all pods to be running. By("Waiting for all pods in the connection checker to be running") - ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute) + timeout := 1 * time.Minute + if windows.ClusterIsWindows() { + timeout = 15 * time.Minute + } + ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() for _, client := range c.clients { - err := e2epod.WaitTimeoutForPodRunningInNamespace(ctx, c.f.ClientSet, client.pod.Name, client.pod.Namespace, 1*time.Minute) + err := e2epod.WaitTimeoutForPodRunningInNamespace(ctx, c.f.ClientSet, client.pod.Name, client.pod.Namespace, timeout) if err != nil { return err } @@ -156,7 +160,7 @@ func (c *connectionTester) deploy() error { client.pod = p } for _, server := range c.servers { - err := e2epod.WaitTimeoutForPodRunningInNamespace(ctx, c.f.ClientSet, server.pod.Name, server.pod.Namespace, 1*time.Minute) + err := e2epod.WaitTimeoutForPodRunningInNamespace(ctx, c.f.ClientSet, server.pod.Name, server.pod.Namespace, timeout) if err != nil { return err } @@ -359,7 +363,11 @@ func (c *connectionTester) Execute() { // Context to control overall timeout for all connections. After it times out, we'll forcefully // terminate any remaining connections. This avoids deadlocking the test waiting for results if // something goes wrong. - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + timeout := 10 * time.Second + if windows.ClusterIsWindows() { + timeout = 20 * time.Second + } + ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() // Launch all of the connections in parallel. We'll wait for them all to finish at the end and report on success / failure. @@ -494,9 +502,7 @@ func (c *connectionTester) command(t Target) string { // Windows. switch t.GetProtocol() { case TCP: - cmd = fmt.Sprintf("$sb={Invoke-WebRequest %s -UseBasicParsing -TimeoutSec 3 -DisableKeepAlive}; "+ - "For ($i=0; $i -lt 5; $i++) { sleep 5; "+ - "try {& $sb} catch { echo failed loop $i ; continue }; exit 0 ; }; exit 1", t.Destination()) + cmd = fmt.Sprintf("Invoke-WebRequest %s -UseBasicParsing -TimeoutSec 5 -DisableKeepAlive -ErrorAction Stop | Out-Null", t.Destination()) case ICMP: cmd = fmt.Sprintf("Test-Connection -Count 5 -ComputerName %s", t.Destination()) default: @@ -595,7 +601,7 @@ func createClientPod(f *framework.Framework, namespace *v1.Namespace, baseName s if windows.ClusterIsWindows() { image = images.WindowsClientImage() command = []string{"powershell.exe"} - args = []string{"Start-Sleep", "600"} + args = []string{"Start-Sleep", "3600"} nodeselector["kubernetes.io/os"] = "windows" } else { image = images.Alpine diff --git a/e2e/pkg/utils/conncheck/k8s.go b/e2e/pkg/utils/conncheck/k8s.go index 6ce45a13c6a..e5165d1265d 100644 --- a/e2e/pkg/utils/conncheck/k8s.go +++ b/e2e/pkg/utils/conncheck/k8s.go @@ -50,7 +50,16 @@ func CreateServerPodAndServiceX(f *framework.Framework, namespace *v1.Namespace, } for _, port := range ports { args := []string{} - if !windows.ClusterIsWindows() { + env := []v1.EnvVar{} + + if windows.ClusterIsWindows() { + env = []v1.EnvVar{ + { + Name: fmt.Sprintf("SERVE_PORT_%d", port), + Value: "foo", + }, + } + } else { args = []string{fmt.Sprintf("--port=%d", port)} } @@ -60,6 +69,7 @@ func CreateServerPodAndServiceX(f *framework.Framework, namespace *v1.Namespace, Image: image, ImagePullPolicy: v1.PullIfNotPresent, Args: args, + Env: env, Ports: []v1.ContainerPort{ { ContainerPort: int32(port),