diff --git a/tests/scripts/testcases_run.sh b/tests/scripts/testcases_run.sh index 02a8efefb61..8ecca92c093 100755 --- a/tests/scripts/testcases_run.sh +++ b/tests/scripts/testcases_run.sh @@ -30,38 +30,16 @@ export ANSIBLE_BECOME_USER=root if [[ "${TESTCASE}" =~ "collection" ]]; then # Build and install collection ansible-galaxy collection build - ansible-galaxy collection install kubernetes_sigs-kubespray-$(grep "^version:" galaxy.yml | awk '{print $2}').tar.gz - - # Simply remove all of our files and directories except for our tests directory - # to be absolutely certain that none of our playbooks or roles - # are interfering with our collection - find -mindepth 1 -maxdepth 1 ! -regex './\(tests\|inventory\)' -exec rm -rfv {} + - -cat > cluster.yml <<EOF -- name: Install Kubernetes - ansible.builtin.import_playbook: kubernetes_sigs.kubespray.cluster -EOF - -cat > upgrade-cluster.yml <<EOF -- name: Install Kubernetes - ansible.builtin.import_playbook: kubernetes_sigs.kubespray.upgrade-cluster -EOF - -cat > reset.yml <<EOF -- name: Remove Kubernetes - ansible.builtin.import_playbook: kubernetes_sigs.kubespray.reset -EOF - -cat > remove-node.yml <<EOF -- name: Remove node from Kubernetes - ansible.builtin.import_playbook: kubernetes_sigs.kubespray.remove_node -EOF - + ansible-galaxy collection install kubernetes_sigs-kubespray-*.tar.gz fi - run_playbook () { -playbook=$1 +if [[ "${TESTCASE}" =~ "collection" ]]; then + playbook=kubernetes_sigs.kubespray.$1 +else + playbook=$1.yml +fi shift + ansible-playbook \ -e @tests/common_vars.yml \ -e @tests/${TESTCASE_FILE} \ @@ -71,11 +49,10 @@ ansible-playbook \ } - ## START KUBESPRAY # Create cluster -run_playbook cluster.yml +run_playbook cluster # Repeat deployment if testing upgrade if [ "${UPGRADE_TEST}" != "false" ]; then @@ -85,10 +62,10 @@ if [ "${UPGRADE_TEST}" != "false" ]; then case "${UPGRADE_TEST}" in "basic") - run_playbook cluster.yml + run_playbook cluster ;; "graceful") - run_playbook upgrade-cluster.yml + run_playbook upgrade-cluster ;; *) ;; @@ -97,36 +74,23 @@ fi # Test control plane recovery if [ "${RECOVER_CONTROL_PLANE_TEST}" != "false" ]; then - run_playbook reset.yml --limit "${RECOVER_CONTROL_PLANE_TEST_GROUPS}" -e reset_confirmation=yes - run_playbook recover-control-plane.yml -e etcd_retries=10 --limit "etcd:kube_control_plane" -fi - -# Tests Cases -## Test Control Plane API -run_playbook tests/testcases/010_check-apiserver.yml -run_playbook tests/testcases/015_check-nodes-ready.yml - -## Test that all nodes are Ready - -if [[ ! ( "$TESTCASE" =~ "macvlan" ) ]]; then - run_playbook tests/testcases/020_check-pods-running.yml - run_playbook tests/testcases/030_check-network.yml - if [[ ! ( "$TESTCASE" =~ "hardening" ) ]]; then - # TODO: We need to remove this condition by finding alternative container - # image instead of netchecker which doesn't work at hardening environments. - run_playbook tests/testcases/040_check-network-adv.yml - fi + run_playbook reset --limit "${RECOVER_CONTROL_PLANE_TEST_GROUPS}" -e reset_confirmation=yes + run_playbook recover-control-plane -e etcd_retries=10 --limit "etcd:kube_control_plane" fi -## Kubernetes conformance tests -run_playbook tests/testcases/100_check-k8s-conformance.yml +# Run tests +ansible-playbook \ + -e @tests/common_vars.yml \ + -e @tests/${TESTCASE_FILE} \ + -e local_release_dir=${PWD}/downloads \ + tests/testcases/tests.yml # Test node removal procedure if [ "${REMOVE_NODE_CHECK}" = "true" ]; then - run_playbook remove-node.yml -e skip_confirmation=yes -e node=${REMOVE_NODE_NAME} + run_playbook remove-node -e skip_confirmation=yes -e node=${REMOVE_NODE_NAME} fi # Clean up at the end, this is to allow stage1 tests to include cleanup test if [ "${RESET_CHECK}" = "true" ]; then - run_playbook reset.yml -e reset_confirmation=yes + run_playbook reset -e reset_confirmation=yes fi diff --git a/tests/testcases/010_check-apiserver.yml b/tests/testcases/010_check-apiserver.yml index 415aa18208e..834851c18f6 100644 --- a/tests/testcases/010_check-apiserver.yml +++ b/tests/testcases/010_check-apiserver.yml @@ -1,21 +1,16 @@ --- -- name: Testcases for apiserver - hosts: kube_control_plane +- name: Check the API servers are responding + uri: + url: "https://{{ (access_ip if (ipv4_stack | default(true)) else access_ip6) | default(ansible_default_ipv4.address if (ipv4_stack | default(true)) else ansible_default_ipv6.address) | ansible.utils.ipwrap }}:{{ kube_apiserver_port | default(6443) }}/version" + validate_certs: false + status_code: 200 + register: apiserver_response + retries: 12 + delay: 5 + until: apiserver_response is success - tasks: - - name: Check the API servers are responding - uri: - url: "https://{{ (access_ip if (ipv4_stack | default(true)) else access_ip6) | default(ansible_default_ipv4.address if (ipv4_stack | default(true)) else ansible_default_ipv6.address) | ansible.utils.ipwrap }}:{{ kube_apiserver_port | default(6443) }}/version" - validate_certs: false - status_code: 200 - register: apiserver_response - retries: 12 - delay: 5 - until: apiserver_response is success - - - name: Check API servers version - assert: - that: - - apiserver_response.json.gitVersion == kube_version - fail_msg: "apiserver version different than expected {{ kube_version }}" - when: kube_version is defined +- name: Check API servers version + assert: + that: + - apiserver_response.json.gitVersion == ('v' + kube_version) + fail_msg: "apiserver is {{ apiserver_response.json.gitVersion }}, expected {{ kube_version }}" diff --git a/tests/testcases/015_check-nodes-ready.yml b/tests/testcases/015_check-nodes-ready.yml index 1b196a58fdf..ee8567e796c 100644 --- a/tests/testcases/015_check-nodes-ready.yml +++ b/tests/testcases/015_check-nodes-ready.yml @@ -1,22 +1,18 @@ --- -- name: Testcases checking nodes - hosts: kube_control_plane[0] - tasks: +- import_role: # noqa name[missing] + name: cluster-dump - - import_role: # noqa name[missing] - name: cluster-dump +- name: Check kubectl output + command: "{{ bin_dir }}/kubectl get nodes" + changed_when: false + register: get_nodes - - name: Check kubectl output - command: "{{ bin_dir }}/kubectl get nodes" - changed_when: false - register: get_nodes - - - name: Check that all nodes are running and ready - command: "{{ bin_dir }}/kubectl get nodes --no-headers -o yaml" - changed_when: false - register: get_nodes_yaml - until: - # Check that all nodes are Status=Ready - - '(get_nodes_yaml.stdout | from_yaml)["items"] | map(attribute = "status.conditions") | map("items2dict", key_name="type", value_name="status") | map(attribute="Ready") | list | min' - retries: 30 - delay: 10 +- name: Check that all nodes are running and ready + command: "{{ bin_dir }}/kubectl get nodes --no-headers -o yaml" + changed_when: false + register: get_nodes_yaml + until: + # Check that all nodes are Status=Ready + - '(get_nodes_yaml.stdout | from_yaml)["items"] | map(attribute = "status.conditions") | map("items2dict", key_name="type", value_name="status") | map(attribute="Ready") | list | min' + retries: 30 + delay: 10 diff --git a/tests/testcases/020_check-pods-running.yml b/tests/testcases/020_check-pods-running.yml index d3f1a4b9fee..ec2025137b2 100644 --- a/tests/testcases/020_check-pods-running.yml +++ b/tests/testcases/020_check-pods-running.yml @@ -1,27 +1,39 @@ --- -- name: Testcases checking pods - hosts: kube_control_plane[0] - tasks: +- import_role: # noqa name[missing] + name: cluster-dump - - import_role: # noqa name[missing] - name: cluster-dump +- name: Check kubectl output + command: "{{ bin_dir }}/kubectl get pods --all-namespaces -owide" + changed_when: false - - name: Check kubectl output - command: "{{ bin_dir }}/kubectl get pods --all-namespaces -owide" - changed_when: false - - - name: Check that all pods are running and ready - command: "{{ bin_dir }}/kubectl get pods --all-namespaces --no-headers -o yaml" - changed_when: false +- name: Check pods + vars: + query_pods_not_running: "items[?status.phase != 'Running']" + query_pods_not_ready: "items[?(status.conditions[?type == 'Ready'])[0].status != 'True']" + pods_not_running: "{{ run_pods_log.stdout | from_json | json_query(query_pods_not_running + '.metadata') }}" + pods_not_ready: "{{ run_pods_log.stdout | from_json | json_query(query_pods_not_ready + '.metadata') }}" + block: + - name: Check that all pods are running + command: "{{ bin_dir }}/kubectl get pods --all-namespaces -o json" register: run_pods_log + changed_when: false until: # Check that all pods are running - - '(run_pods_log.stdout | from_yaml)["items"] | map(attribute = "status.phase") | unique | list == ["Running"]' + - run_pods_log.stdout | from_json | json_query(query_pods_not_running) == [] # Check that all pods are ready - - '(run_pods_log.stdout | from_yaml)["items"] | map(attribute = "status.containerStatuses") | map("map", attribute = "ready") | map("min") | min' + - run_pods_log.stdout | from_json | json_query(query_pods_not_ready) == [] retries: 30 delay: 10 - - - name: Check kubectl output - command: "{{ bin_dir }}/kubectl get pods --all-namespaces -owide" - changed_when: false + rescue: + - name: Describe broken pods + command: "{{ bin_dir }}/kubectl describe pod -n {{ item.namespace }} {{ item.name }}" + loop: "{{ pods_not_running + pods_not_ready }}" + loop_control: + label: "{{ item.namespace }}/{{ item.name }}" + - name: Get logs from broken pods + command: "{{ bin_dir }}/kubectl logs -n {{ item.namespace }} {{ item.pod }}" + loop: "{{ pods_not_running + pods_not_ready }}" + loop_control: + label: "{{ item.namespace }}/{{ item.name }}" + - name: Fail CI + fail: {} diff --git a/tests/testcases/030_check-network.yml b/tests/testcases/030_check-network.yml index 4d0ab78b7a8..28d869efcf5 100644 --- a/tests/testcases/030_check-network.yml +++ b/tests/testcases/030_check-network.yml @@ -1,128 +1,119 @@ --- -- name: Testcases for network - hosts: kube_control_plane[0] +- name: Check kubelet serving certificates approved with kubelet_csr_approver + when: + - kubelet_rotate_server_certificates | default(false) + - kubelet_csr_approver_enabled | default(kubelet_rotate_server_certificates | default(false)) vars: - test_image_repo: registry.k8s.io/e2e-test-images/agnhost - test_image_tag: "2.40" - # TODO: source those from kubespray_defaults instead. - # Needs kubespray_defaults to be decoupled from no-proxy stuff - kube_pods_subnet: "{{ 'fd85:ee78:d8a6:8607::1:0000/112' if not (ipv4_stack | default(true)) else '10.233.64.0/18' }}" + csrs: "{{ csr_json.stdout | from_json }}" + block: - tasks: - - - name: Check kubelet serving certificates approved with kubelet_csr_approver - when: - - kubelet_rotate_server_certificates | default(false) - - kubelet_csr_approver_enabled | default(kubelet_rotate_server_certificates | default(false)) - vars: - csrs: "{{ csr_json.stdout | from_json }}" - block: - - - name: Get certificate signing requests - command: "{{ bin_dir }}/kubectl get csr -o jsonpath-as-json={.items[*]}" - register: csr_json - changed_when: false - - - name: Check there are csrs - assert: - that: csrs | length > 0 - fail_msg: kubelet_rotate_server_certificates is {{ kubelet_rotate_server_certificates }} but no csr's found - - - name: Check there are Denied/Pending csrs - assert: - that: - - csrs | rejectattr('status') | length == 0 # Pending == no status - - csrs | map(attribute='status.conditions') | flatten | selectattr('type', 'equalto', 'Denied') | length == 0 # Denied - - fail_msg: kubelet_csr_approver is enabled but CSRs are not approved + - name: Get certificate signing requests + command: "{{ bin_dir }}/kubectl get csr -o jsonpath-as-json={.items[*]}" + register: csr_json + changed_when: false - - name: Approve kubelet serving certificates - when: - - kubelet_rotate_server_certificates | default(false) - - not (kubelet_csr_approver_enabled | default(kubelet_rotate_server_certificates | default(false))) - block: + - name: Check there are csrs + assert: + that: csrs | length > 0 + fail_msg: kubelet_rotate_server_certificates is {{ kubelet_rotate_server_certificates }} but no csr's found - - name: Get certificate signing requests - command: "{{ bin_dir }}/kubectl get csr -o name" - register: get_csr - changed_when: false + - name: Check there are Denied/Pending csrs + assert: + that: + - csrs | rejectattr('status') | length == 0 # Pending == no status + - csrs | map(attribute='status.conditions') | flatten | selectattr('type', 'equalto', 'Denied') | length == 0 # Denied - - name: Check there are csrs - assert: - that: get_csr.stdout_lines | length > 0 - fail_msg: kubelet_rotate_server_certificates is {{ kubelet_rotate_server_certificates }} but no csr's found + fail_msg: kubelet_csr_approver is enabled but CSRs are not approved - - name: Approve certificates - command: "{{ bin_dir }}/kubectl certificate approve {{ get_csr.stdout_lines | join(' ') }}" - register: certificate_approve - when: get_csr.stdout_lines | length > 0 - changed_when: certificate_approve.stdout +- name: Approve kubelet serving certificates + when: + - kubelet_rotate_server_certificates | default(false) + - not (kubelet_csr_approver_enabled | default(kubelet_rotate_server_certificates | default(false))) + block: - - name: Create test namespace - command: "{{ bin_dir }}/kubectl create namespace test" + - name: Get certificate signing requests + command: "{{ bin_dir }}/kubectl get csr -o name" + register: get_csr changed_when: false - - name: Run 2 agnhost pods in test ns - command: - cmd: "{{ bin_dir }}/kubectl apply --namespace test -f -" - stdin: | - apiVersion: apps/v1 - kind: Deployment - metadata: - name: agnhost - spec: - replicas: 2 - selector: - matchLabels: + - name: Check there are csrs + assert: + that: get_csr.stdout_lines | length > 0 + fail_msg: kubelet_rotate_server_certificates is {{ kubelet_rotate_server_certificates }} but no csr's found + + - name: Approve certificates + command: "{{ bin_dir }}/kubectl certificate approve {{ get_csr.stdout_lines | join(' ') }}" + register: certificate_approve + when: get_csr.stdout_lines | length > 0 + changed_when: certificate_approve.stdout + +- name: Create test namespace + command: "{{ bin_dir }}/kubectl create namespace test" + changed_when: false + +- name: Run 2 agnhost pods in test ns + command: + cmd: "{{ bin_dir }}/kubectl apply --namespace test -f -" + stdin: | + apiVersion: apps/v1 + kind: Deployment + metadata: + name: agnhost + spec: + replicas: 2 + selector: + matchLabels: + app: agnhost + template: + metadata: + labels: app: agnhost - template: - metadata: - labels: - app: agnhost - spec: - containers: - - name: agnhost - image: {{ test_image_repo }}:{{ test_image_tag }} - command: ['/agnhost', 'netexec', '--http-port=8080'] - securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: ['ALL'] - runAsUser: 1000 - runAsNonRoot: true - seccompProfile: - type: RuntimeDefault + spec: + containers: + - name: agnhost + image: {{ test_image_repo }}:{{ test_image_tag }} + command: ['/agnhost', 'netexec', '--http-port=8080'] + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: ['ALL'] + runAsUser: 1000 + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + changed_when: false + +- name: Check that all pods are running and ready + vars: + pods: "{{ (pods_json.stdout | from_json)['items'] }}" + block: + - name: Check Deployment is ready + command: "{{ bin_dir }}/kubectl rollout status deploy --namespace test agnhost --timeout=180s" + changed_when: false + - name: Get pod names + command: "{{ bin_dir }}/kubectl get pods -n test -o json" + changed_when: false + register: pods_json + + - name: Check pods IP are in correct network + assert: + that: pods + | selectattr('status.phase', '==', 'Running') + | selectattr('status.podIP', 'ansible.utils.in_network', kube_pods_subnet) + | length == 2 + + - name: Curl between pods is working + command: "{{ bin_dir }}/kubectl -n test exec {{ item[0].metadata.name }} -- curl {{ item[1].status.podIP | ansible.utils.ipwrap}}:8080" + with_nested: + - "{{ pods }}" + - "{{ pods }}" + loop_control: + label: "{{ item[0].metadata.name + ' --> ' + item[1].metadata.name }}" + rescue: + - name: List pods cluster-wide + command: "{{ bin_dir }}/kubectl get pods --all-namespaces -owide" changed_when: false - - name: Check that all pods are running and ready - vars: - pods: "{{ (pods_json.stdout | from_json)['items'] }}" - block: - - name: Check Deployment is ready - command: "{{ bin_dir }}/kubectl rollout status deploy --namespace test agnhost --timeout=180s" - changed_when: false - - name: Get pod names - command: "{{ bin_dir }}/kubectl get pods -n test -o json" - changed_when: false - register: pods_json - - - name: Check pods IP are in correct network - assert: - that: pods - | selectattr('status.phase', '==', 'Running') - | selectattr('status.podIP', 'ansible.utils.in_network', kube_pods_subnet) - | length == 2 - - - name: Curl between pods is working - command: "{{ bin_dir }}/kubectl -n test exec {{ item[0].metadata.name }} -- curl {{ item[1].status.podIP | ansible.utils.ipwrap}}:8080" - with_nested: - - "{{ pods }}" - - "{{ pods }}" - rescue: - - name: List pods cluster-wide - command: "{{ bin_dir }}/kubectl get pods --all-namespaces -owide" - changed_when: false - - - import_role: # noqa name[missing] - name: cluster-dump - - fail: # noqa name[missing] + - import_role: # noqa name[missing] + name: cluster-dump + - fail: # noqa name[missing] diff --git a/tests/testcases/040_check-network-adv.yml b/tests/testcases/040_check-network-adv.yml index 9f40e10f582..7f02f8c8ed9 100644 --- a/tests/testcases/040_check-network-adv.yml +++ b/tests/testcases/040_check-network-adv.yml @@ -1,160 +1,149 @@ --- -- name: Testcases for calico - hosts: kube_node - tasks: - - name: Test tunl0 routes - command: "/sbin/ip route" - register: routes - failed_when: routes.stdout_lines - | select('contains', '/' ~ calico_pool_blocksize|d(26)) - | select('contains', 'tunl0') | length == 0 - when: - - (calico_ipip_mode is defined and calico_ipip_mode != 'Never') - - kube_network_plugin | default('calico') == 'calico' +- name: Test tunl0 routes + command: "/sbin/ip route" + register: routes + failed_when: routes.stdout_lines + | select('contains', '/' ~ calico_pool_blocksize|d(26)) + | select('contains', 'tunl0') | length == 0 + when: + - ('kube_node' in group_names) + - (calico_ipip_mode is defined and calico_ipip_mode != 'Never') + - kube_network_plugin | default('calico') == 'calico' +- import_role: # noqa name[missing] + name: cluster-dump -- name: Advanced testcases for network - hosts: k8s_cluster - vars: - agent_report_interval: 10 - netcheck_namespace: default - netchecker_port: 31081 +- name: Wait for netchecker server + command: "{{ bin_dir }}/kubectl get pods --field-selector=status.phase==Running -o jsonpath-as-json={.items[*].metadata.name} --namespace {{ netcheck_namespace }}" + register: pods_json + until: + - pods_json.stdout | from_json | select('match', 'netchecker-server.*') | length == 1 + - (pods_json.stdout | from_json | select('match', 'netchecker-agent.*') | length) + >= (groups['k8s_cluster'] | intersect(ansible_play_hosts) | length * 2) + retries: 3 + delay: 10 + when: inventory_hostname == groups['kube_control_plane'][0] - tasks: - - import_role: # noqa name[missing] - name: cluster-dump +- name: Get netchecker pods + command: "{{ bin_dir }}/kubectl -n {{ netcheck_namespace }} describe pod -l app={{ item }}" + run_once: true + delegate_to: "{{ groups['kube_control_plane'][0] }}" + with_items: + - netchecker-agent + - netchecker-agent-hostnet + when: not pods_json is success - - name: Wait for netchecker server - command: "{{ bin_dir }}/kubectl get pods --field-selector=status.phase==Running -o jsonpath-as-json={.items[*].metadata.name} --namespace {{ netcheck_namespace }}" - register: pods_json +- name: Perform netchecker tests + run_once: true + delegate_to: "{{ groups['kube_control_plane'][0] }}" + block: + - name: Get netchecker agents + uri: + url: "http://{{ (ansible_default_ipv6.address if not (ipv4_stack | default(true)) else ansible_default_ipv4.address) | ansible.utils.ipwrap }}:{{ netchecker_port }}/api/v1/agents/" + return_content: true + headers: + Accept: application/json + register: agents + retries: 18 + delay: "{{ agent_report_interval }}" until: - - pods_json.stdout | from_json | select('match', 'netchecker-server.*') | length == 1 - - (pods_json.stdout | from_json | select('match', 'netchecker-agent.*') | length) - >= (groups['k8s_cluster'] | intersect(ansible_play_hosts) | length * 2) - retries: 3 - delay: 10 - when: inventory_hostname == groups['kube_control_plane'][0] - - - name: Get netchecker pods - command: "{{ bin_dir }}/kubectl -n {{ netcheck_namespace }} describe pod -l app={{ item }}" - run_once: true - delegate_to: "{{ groups['kube_control_plane'][0] }}" - with_items: - - netchecker-agent - - netchecker-agent-hostnet - when: not pods_json is success - - - name: Perform netchecker tests - run_once: true - delegate_to: "{{ groups['kube_control_plane'][0] }}" - block: - - name: Get netchecker agents - uri: - url: "http://{{ (ansible_default_ipv6.address if not (ipv4_stack | default(true)) else ansible_default_ipv4.address) | ansible.utils.ipwrap }}:{{ netchecker_port }}/api/v1/agents/" - return_content: true - headers: - Accept: application/json - register: agents - retries: 18 - delay: "{{ agent_report_interval }}" - until: - - agents is success - - (agents.content | from_json | length) == (groups['k8s_cluster'] | length * 2) + - agents is success + - (agents.content | from_json | length) == (groups['k8s_cluster'] | length * 2) - - name: Check netchecker status - uri: - url: "http://{{ (ansible_default_ipv6.address if not (ipv4_stack | default(true)) else ansible_default_ipv4.address) | ansible.utils.ipwrap }}:{{ netchecker_port }}/api/v1/connectivity_check" - return_content: true - headers: - Accept: application/json - register: connectivity_check - retries: 3 - delay: "{{ agent_report_interval }}" - until: - - connectivity_check is success - - connectivity_check.content | from_json + - name: Check netchecker status + uri: + url: "http://{{ (ansible_default_ipv6.address if not (ipv4_stack | default(true)) else ansible_default_ipv4.address) | ansible.utils.ipwrap }}:{{ netchecker_port }}/api/v1/connectivity_check" + return_content: true + headers: + Accept: application/json + register: connectivity_check + retries: 3 + delay: "{{ agent_report_interval }}" + until: + - connectivity_check is success + - connectivity_check.content | from_json - rescue: - - name: Get kube-proxy logs - command: "{{ bin_dir }}/kubectl -n kube-system logs -l k8s-app=kube-proxy" + rescue: + - name: Get kube-proxy logs + command: "{{ bin_dir }}/kubectl -n kube-system logs -l k8s-app=kube-proxy" - - name: Get logs from other apps - command: "{{ bin_dir }}/kubectl -n kube-system logs -l k8s-app={{ item }} --all-containers" - with_items: - - kube-router - - flannel - - canal-node - - calico-node - - cilium + - name: Get logs from other apps + command: "{{ bin_dir }}/kubectl -n kube-system logs -l k8s-app={{ item }} --all-containers" + with_items: + - kube-router + - flannel + - canal-node + - calico-node + - cilium - - name: Netchecker tests failed - fail: - msg: "netchecker tests failed" + - name: Netchecker tests failed + fail: + msg: "netchecker tests failed" - - name: Check connectivity with all netchecker agents - vars: - connectivity_check_result: "{{ connectivity_check.content | from_json }}" - agents_check_result: "{{ agents.content | from_json }}" - assert: - that: - - agents_check_result is defined - - connectivity_check_result is defined - - agents_check_result.keys() | length > 0 - - not connectivity_check_result.Absent - - not connectivity_check_result.Outdated - msg: "Connectivity check to netchecker agents failed" - delegate_to: "{{ groups['kube_control_plane'][0] }}" - run_once: true +- name: Check connectivity with all netchecker agents + vars: + connectivity_check_result: "{{ connectivity_check.content | from_json }}" + agents_check_result: "{{ agents.content | from_json }}" + assert: + that: + - agents_check_result is defined + - connectivity_check_result is defined + - agents_check_result.keys() | length > 0 + - not connectivity_check_result.Absent + - not connectivity_check_result.Outdated + msg: "Connectivity check to netchecker agents failed" + delegate_to: "{{ groups['kube_control_plane'][0] }}" + run_once: true - - name: Create macvlan network conf - command: - cmd: "{{ bin_dir }}/kubectl create -f -" - stdin: | - apiVersion: "k8s.cni.cncf.io/v1" - kind: NetworkAttachmentDefinition - metadata: - name: macvlan-conf - spec: - config: '{ - "cniVersion": "0.4.0", - "type": "macvlan", - "master": "eth0", - "mode": "bridge", - "ipam": { - "type": "host-local", - "subnet": "192.168.1.0/24", - "rangeStart": "192.168.1.200", - "rangeEnd": "192.168.1.216", - "routes": [ - { "dst": "0.0.0.0/0" } - ], - "gateway": "192.168.1.1" - } - }' - --- - apiVersion: v1 - kind: Pod - metadata: - name: samplepod - annotations: - k8s.v1.cni.cncf.io/networks: macvlan-conf - spec: - containers: - - name: samplepod - command: ["/bin/bash", "-c", "sleep 2000000000000"] - image: dougbtv/centos-network - delegate_to: groups['kube_control_plane'][0] - run_once: true - when: - - kube_network_plugin_multus | default(false) | bool +- name: Create macvlan network conf + command: + cmd: "{{ bin_dir }}/kubectl create -f -" + stdin: | + apiVersion: "k8s.cni.cncf.io/v1" + kind: NetworkAttachmentDefinition + metadata: + name: macvlan-conf + spec: + config: '{ + "cniVersion": "0.4.0", + "type": "macvlan", + "master": "eth0", + "mode": "bridge", + "ipam": { + "type": "host-local", + "subnet": "192.168.1.0/24", + "rangeStart": "192.168.1.200", + "rangeEnd": "192.168.1.216", + "routes": [ + { "dst": "0.0.0.0/0" } + ], + "gateway": "192.168.1.1" + } + }' + --- + apiVersion: v1 + kind: Pod + metadata: + name: samplepod + annotations: + k8s.v1.cni.cncf.io/networks: macvlan-conf + spec: + containers: + - name: samplepod + command: ["/bin/bash", "-c", "sleep 2000000000000"] + image: dougbtv/centos-network + delegate_to: groups['kube_control_plane'][0] + run_once: true + when: + - kube_network_plugin_multus | default(false) | bool - - name: Check secondary macvlan interface - command: "{{ bin_dir }}/kubectl exec samplepod -- ip addr show dev net1" - register: output - until: output.rc == 0 - retries: 90 - changed_when: false - delegate_to: groups['kube_control_plane'][0] - run_once: true - when: - - kube_network_plugin_multus | default(false) | bool +- name: Check secondary macvlan interface + command: "{{ bin_dir }}/kubectl exec samplepod -- ip addr show dev net1" + register: output + until: output.rc == 0 + retries: 90 + changed_when: false + delegate_to: groups['kube_control_plane'][0] + run_once: true + when: + - kube_network_plugin_multus | default(false) | bool diff --git a/tests/testcases/100_check-k8s-conformance.yml b/tests/testcases/100_check-k8s-conformance.yml index 3e0f17109dd..56687fb034f 100644 --- a/tests/testcases/100_check-k8s-conformance.yml +++ b/tests/testcases/100_check-k8s-conformance.yml @@ -1,38 +1,22 @@ --- -- name: Testcases for kubernetes conformance - hosts: kube_control_plane[0] - vars: - sonobuoy_version: 0.56.11 - sonobuoy_arch: amd64 - sonobuoy_parallel: 30 - sonobuoy_path: /usr/local/bin/sonobuoy - sonobuoy_mode: Quick +- name: Download sonobuoy + get_url: + url: "https://github.com/vmware-tanzu/sonobuoy/releases/download/v{{ sonobuoy_version }}/sonobuoy_{{ sonobuoy_version }}_linux_{{ sonobuoy_arch }}.tar.gz" + dest: /tmp/sonobuoy.tar.gz + mode: "0644" - tasks: - - name: Run sonobuoy - when: - - sonobuoy_enabled is defined - - sonobuoy_enabled - block: - - name: Download sonobuoy - get_url: - url: "https://github.com/heptio/sonobuoy/releases/download/v{{ sonobuoy_version }}/sonobuoy_{{ sonobuoy_version }}_linux_{{ sonobuoy_arch }}.tar.gz" - dest: /tmp/sonobuoy.tar.gz - mode: "0644" +- name: Extract sonobuoy + unarchive: + src: /tmp/sonobuoy.tar.gz + dest: /usr/local/bin/ + copy: false - - name: Extract sonobuoy - unarchive: - src: /tmp/sonobuoy.tar.gz - dest: /usr/local/bin/ - copy: false +- name: Run sonobuoy + command: "{{ sonobuoy_path }} run --mode {{ sonobuoy_mode }} --e2e-parallel {{ sonobuoy_parallel }} --wait" - - name: Run sonobuoy - command: "{{ sonobuoy_path }} run --mode {{ sonobuoy_mode }} --e2e-parallel {{ sonobuoy_parallel }} --wait" - when: sonobuoy_enabled | default(false) +- name: Run sonobuoy retrieve + command: "{{ sonobuoy_path }} retrieve" + register: sonobuoy_retrieve - - name: Run sonobuoy retrieve - command: "{{ sonobuoy_path }} retrieve" - register: sonobuoy_retrieve - - - name: Run inspect results - command: "{{ sonobuoy_path }} results {{ sonobuoy_retrieve.stdout }} --plugin e2e --mode report" +- name: Run inspect results + command: "{{ sonobuoy_path }} results {{ sonobuoy_retrieve.stdout }} --plugin e2e --mode report" diff --git a/tests/testcases/tests.yml b/tests/testcases/tests.yml new file mode 100644 index 00000000000..f9987cd9fcd --- /dev/null +++ b/tests/testcases/tests.yml @@ -0,0 +1,54 @@ +--- +- name: Define dynamic groups + import_playbook: ../../playbooks/boilerplate.yml + +- name: Kubespray CI tests + hosts: k8s_cluster + gather_facts: false + vars: + testcase: "{{ lookup('env', 'TESTCASE') }}" + tasks: + - name: Import Kubespray variables + import_role: + name: ../../roles/kubespray_defaults + - name: Testcases for apiserver + import_tasks: 010_check-apiserver.yml + when: + - ('kube_control_plane') in group_names + - name: Test using API + delegate_to: "{{ groups['kube_control_plane'][0] }}" + run_once: true + block: + - name: Testcases checking nodes + import_tasks: 015_check-nodes-ready.yml + - name: Testcases checking pods + import_tasks: 020_check-pods-running.yml + when: ('macvlan' not in testcase) + - name: Testcases for network + import_tasks: 030_check-network.yml + when: ('macvlan' not in testcase) + vars: + test_image_repo: registry.k8s.io/e2e-test-images/agnhost + test_image_tag: "2.40" + - name: Testcases for calico / advanced network + import_tasks: 040_check-network-adv.yml + when: + - ('macvlan' not in testcase) + - ('hardening' not in testcase) + vars: + agent_report_interval: 10 + netcheck_namespace: default + netchecker_port: 31081 + - name: Testcases for kubernetes conformance + import_tasks: 100_check-k8s-conformance.yml + delegate_to: "{{ groups['kube_control_plane'][0] }}" + run_once: true + when: + - sonobuoy_enabled is defined + - sonobuoy_enabled + vars: + sonobuoy_version: 0.56.11 + sonobuoy_arch: amd64 + sonobuoy_parallel: 30 + sonobuoy_path: /usr/local/bin/sonobuoy + sonobuoy_mode: Quick