From 198d885b8f1fa6d752cd52819b627e51f588121b Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Thu, 27 Jul 2023 14:50:08 +0200 Subject: [PATCH] ci: integration tests Signed-off-by: Guido Grazioli --- .ansible-lint | 35 ++ .github/workflows/ci.yml | 174 ++-------- .github/workflows/docs.yml | 2 + .github/workflows/integration.yml | 224 ++++++++++++ .github/workflows/release.yml | 2 + changelogs/config.yaml | 32 +- docs/index.rst | 6 +- examples/play-create-dv.yml | 25 +- examples/play-create-min.yml | 3 +- examples/play-create.yml | 41 +-- examples/play-delete-dv.yml | 3 +- examples/play-delete.yml | 3 +- examples/services.kubevirt.yml | 2 +- galaxy.yml | 8 +- .../targets/inventory_kubevirt/playbook.yml | 62 ++++ .../targets/inventory_kubevirt/runme.sh | 74 ++-- .../targets/inventory_kubevirt/server.py | 322 ------------------ .../inventory_kubevirt/test.kubevirt.yml | 4 + .../test.label.kubevirt.yml | 5 + .../inventory_kubevirt/test.net.kubevirt.yml | 5 + .../targets/inventory_kubevirt/test.out | 124 ------- .../targets/inventory_kubevirt/verify.yml | 35 ++ .../targets/kubevirt_vm/playbook.yml | 43 +++ .../integration/targets/kubevirt_vm/runme.sh | 21 ++ .../targets/kubevirt_vm/test.kubevirt.yml | 5 + .../targets/kubevirt_vm/verify.yml | 69 ++++ 26 files changed, 626 insertions(+), 703 deletions(-) create mode 100644 .ansible-lint create mode 100644 .github/workflows/integration.yml create mode 100644 tests/integration/targets/inventory_kubevirt/playbook.yml delete mode 100755 tests/integration/targets/inventory_kubevirt/server.py create mode 100644 tests/integration/targets/inventory_kubevirt/test.kubevirt.yml create mode 100644 tests/integration/targets/inventory_kubevirt/test.label.kubevirt.yml create mode 100644 tests/integration/targets/inventory_kubevirt/test.net.kubevirt.yml delete mode 100644 tests/integration/targets/inventory_kubevirt/test.out create mode 100644 tests/integration/targets/inventory_kubevirt/verify.yml create mode 100644 tests/integration/targets/kubevirt_vm/playbook.yml create mode 100755 tests/integration/targets/kubevirt_vm/runme.sh create mode 100644 tests/integration/targets/kubevirt_vm/test.kubevirt.yml create mode 100644 tests/integration/targets/kubevirt_vm/verify.yml diff --git a/.ansible-lint b/.ansible-lint new file mode 100644 index 0000000..9705508 --- /dev/null +++ b/.ansible-lint @@ -0,0 +1,35 @@ +# .ansible-lint +exclude_paths: + - .cache/ + - .github/ + - molecule/ + - .ansible-lint + - .yamllint + - meta/ + - playbooks/roles/ + +enable_list: + - fqcn-builtins # opt-in + - no-log-password # opt-in + +warn_list: + - experimental + - ignore-errors + - no-handler + - fqcn-builtins + - no-log-password + - no-empty-data-files + - name[template] + - fqcn[keyword] + - schema[meta] + - no-free-form + - run-once[task] + - var-naming[no-role-prefix] + - yaml[truthy] + - galaxy[version-incorrect] + +skip_list: + - jinja[spacing] + +use_default_rules: true +parseable: true diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aadc389..095153e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,7 @@ name: CI +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true on: push: branches: @@ -7,11 +10,11 @@ on: schedule: - cron: '0 6 * * *' jobs: - prereq: + linter: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: path: ansible_collections/kubevirt/core fetch-depth: 0 @@ -19,8 +22,24 @@ jobs: mkdir -p /home/runner/.kube/ cp -rp ${GITHUB_WORKSPACE}/ansible_collections/kubevirt/core/tests/.kubeconfig /home/runner/.kube/config cat /home/runner/.kube/config + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.11' + cache: 'pip' + - name: Install yamllint, ansible + run: | + python -m pip install --upgrade pip + pip install yamllint ansible-core ansible-lint + - name: Run linter + run: | + ansible-lint --version + ansible-lint -v + working-directory: ./ansible_collections/kubevirt/core sanity: uses: ansible-network/github_actions/.github/workflows/sanity.yml@main + needs: + - linter with: matrix_include: "[]" matrix_exclude: >- @@ -92,7 +111,7 @@ jobs: unit-source: uses: ansible-network/github_actions/.github/workflows/unit_source.yml@main needs: - - prereq + - linter with: matrix_exclude: >- [ @@ -153,149 +172,18 @@ jobs: } ] collection_pre_install: '' - splitter: - env: - source_dir: "./source" - runs-on: ubuntu-latest - outputs: - test_targets: ${{ steps.display.outputs.test_targets }} - steps: - - name: Checkout the collection repository - uses: actions/checkout@v3 - with: - path: ${{ env.source_dir }} - fetch-depth: "0" - - - name: list changes for pull request - id: splitter - uses: ansible-network/github_actions/.github/actions/ansible_test_splitter@main - with: - collections_to_test: ${{ env.source_dir }} - total_jobs: 8 - - - name: display targets - id: display - run: echo "test_targets=${{ steps.splitter.outputs.test_targets }}" >> $GITHUB_OUTPUT - shell: bash - integration: + uses: guidograzioli/kubernetes.kubevirt/.github/workflows/integration.yml@integration_tests needs: - - splitter - env: - source: "./source" - cloud_common: "./cloudcommon" - ansible_posix: "./ansible_posix" - test_targets: ${{ needs.splitter.outputs.test_targets }} - runs-on: ubuntu-latest - timeout-minutes: 60 - strategy: - fail-fast: false - matrix: - ansible-version: - - stable-2.12 - - milestone - - devel - python-version: - - "3.8" - - "3.9" - exclude: - - ansible-version: stable-2.9 - python-version: 3.9 - - ansible-version: stable-2.9 - python-version: 3.10 - - ansible-version: stable-2.9 - python-version: 3.11 - - ansible-version: stable-2.12 - python-version: 3.11 - - ansible-version: stable-2.13 - python-version: 3.11 - - ansible-version: stable-2.14 - python-version: 3.8 - - ansible-version: stable-2.15 - python-version: 3.8 - - ansible-version: milestone - python-version: 3.8 - - ansible-version: devel - python-version: 3.8 - enable-turbo-mode: - - true - - false - job-index: [1, 2, 3, 4, 5, 6, 7, 8] - name: "integration-py${{ matrix.python-version }}-${{ matrix.ansible-version }}-turbo-mode=${{ matrix.enable-turbo-mode }}-${{ matrix.job-index }}" - steps: - - name: Read ansible-test targets - id: read-targets - run: >- - echo "ansible_test_targets=$(echo "${{ env.test_targets }}" | sed s/';'/'\n'/g | - grep "kubernetes.core-${{ matrix.job-index }}" | cut -d ':' -f2 | sed s/','/' '/g)" >> $GITHUB_OUTPUT - shell: bash - - - name: Display targets - run: >- - echo "targets to test: $ANSIBLE_TARGETS" - shell: bash - env: - ANSIBLE_TARGETS: ${{ steps.read-targets.outputs.ansible_test_targets }} - - - name: Checkout kubernetes.core repository - uses: actions/checkout@v3 - with: - path: ${{ env.source }} - fetch-depth: "0" - if: steps.read-targets.outputs.ansible_test_targets != '' - - - name: checkout ansible-collections/cloud.common - uses: ansible-network/github_actions/.github/actions/checkout_dependency@main - with: - repository: ansible-collections/cloud.common - path: ${{ env.cloud_common }} - ref: main - if: steps.read-targets.outputs.ansible_test_targets != '' - - - name: checkout ansible-collections/ansible.posix - uses: ansible-network/github_actions/.github/actions/checkout_dependency@main - with: - repository: ansible-collections/ansible.posix - path: ${{ env.ansible_posix }} - ref: main - if: steps.read-targets.outputs.ansible_test_targets != '' - - - name: install kubernetes.core collection - id: install-collection - uses: ansible-network/github_actions/.github/actions/build_install_collection@main - with: - install_python_dependencies: true - source_path: ${{ env.source }} - if: steps.read-targets.outputs.ansible_test_targets != '' - - - name: install cloud.common collection - uses: ansible-network/github_actions/.github/actions/build_install_collection@main - with: - install_python_dependencies: true - source_path: ${{ env.cloud_common }} - if: steps.read-targets.outputs.ansible_test_targets != '' - - - name: install ansible.posix collection - uses: ansible-network/github_actions/.github/actions/build_install_collection@main - with: - install_python_dependencies: true - source_path: ${{ env.ansible_posix }} - if: steps.read-targets.outputs.ansible_test_targets != '' - - - name: create kubernetes cluster - uses: helm/kind-action@v1.4.0 - if: steps.read-targets.outputs.ansible_test_targets != '' + - unit-source + with: + ansible_test_targets: >- + [ + "kubevirt_vm", + "inventory_kubevirt" + ] + name: "integration" - - name: Run integration tests - uses: ansible-network/github_actions/.github/actions/ansible_test_integration@main - with: - collection_path: ${{ steps.install-collection.outputs.collection_path }} - python_version: ${{ matrix.python-version }} - ansible_version: ${{ matrix.ansible-version }} - ansible_test_targets: ${{ steps.read-targets.outputs.ansible_test_targets }} - ansible_test_environment: | - ENABLE_TURBO_MODE=${{ matrix.enable-turbo-mode }} - if: steps.read-targets.outputs.ansible_test_targets != '' all_green: if: ${{ always() }} needs: diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 1b29538..a3a5abd 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -62,3 +62,5 @@ jobs: generate_docs: true path: /home/runner/.ansible/collections/ansible_collections/kubevirt/core token: ${{ secrets.GITHUB_TOKEN }} + bot_email: kubevirtbot@redhat.com + bot_account: kubevirt-bot diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml new file mode 100644 index 0000000..4abcbc5 --- /dev/null +++ b/.github/workflows/integration.yml @@ -0,0 +1,224 @@ +name: Integration tests +on: + workflow_call: + inputs: + matrix_exclude: + # https://docs.ansible.com/ansible/latest/reference_appendices/release_and_maintenance.html#ansible-core-support-matrix + # 2.9 supports Python 3.5-3.8 + # 2.13 supports Python 3.8-3.10 + # 2.14 supports Python 3.9-3.11 + # 2.15 supports Python 3.9-3.11 + # 2.16 supports Python 3.10-3.11 + # https://docs.ansible.com/ansible/devel/roadmap/ROADMAP_2_16.html + # milestone is 2.16 until after 2.16 branches from devel + # devel is 2.16 until 2023-09-18 + default: >- + [ + { + "ansible-version": "stable-2.9", + "python-version": "3.9" + }, + { + "ansible-version": "stable-2.9", + "python-version": "3.10" + }, + { + "ansible-version": "stable-2.9", + "python-version": "3.11" + }, + { + "ansible-version": "stable-2.12", + "python-version": "3.11" + }, + { + "ansible-version": "stable-2.13", + "python-version": "3.7" + }, + { + "ansible-version": "stable-2.13", + "python-version": "3.11" + }, + { + "ansible-version": "stable-2.14", + "python-version": "3.7" + }, + { + "ansible-version": "stable-2.14", + "python-version": "3.8" + }, + { + "ansible-version": "stable-2.15", + "python-version": "3.7" + }, + { + "ansible-version": "stable-2.15", + "python-version": "3.8" + }, + { + "ansible-version": "milestone", + "python-version": "3.7" + }, + { + "ansible-version": "milestone", + "python-version": "3.8" + }, + { + "ansible-version": "milestone", + "python-version": "3.9" + }, + { + "ansible-version": "devel", + "python-version": "3.7" + }, + { + "ansible-version": "devel", + "python-version": "3.8" + }, + { + "ansible-version": "devel", + "python-version": "3.9" + } + ] + required: false + type: string + matrix_include: + # python 3.6 is not available after ubuntu-20.04 + # python 3.6 is not supported on ansible 2.12+ + default: >- + [] + required: false + type: string + unstable: + default: >- + [ + "devel", + ] + required: false + type: string + ansible_test_targets: + required: true + type: string +jobs: + integration: + env: + PY_COLORS: "1" + source: "./source" + core: "./core" + cloud_common: "./cloudcommon" + ansible_posix: "./ansible_posix" + strategy: + fail-fast: false + matrix: + test-target: ${{ fromJSON(inputs.ansible_test_targets) }} + ansible-version: + - stable-2.9 + - stable-2.12 + - stable-2.14 + - stable-2.15 + - milestone + - devel + python-version: + - "3.8" + - "3.9" + - "3.11" + exclude: ${{ fromJSON(inputs.matrix_exclude) }} + include: ${{ fromJSON(inputs.matrix_include) }} + runs-on: ubuntu-latest + continue-on-error: ${{ contains(fromJSON(inputs.unstable), matrix.ansible-version) }} + + name: "${{ matrix.test-target }} / py${{ matrix.python-version }} / ${{ matrix.ansible-version }}" + steps: + - name: Checkout kubernetes.core repository + uses: actions/checkout@v3 + with: + path: ${{ env.core }} + fetch-depth: "0" + if: inputs.ansible_test_targets != '' + + - name: checkout ansible-collections/cloud.common + uses: ansible-network/github_actions/.github/actions/checkout_dependency@main + with: + repository: ansible-collections/cloud.common + path: ${{ env.cloud_common }} + ref: main + if: inputs.ansible_test_targets != '' + + - name: checkout ansible-collections/ansible.posix + uses: ansible-network/github_actions/.github/actions/checkout_dependency@main + with: + repository: ansible-collections/ansible.posix + path: ${{ env.ansible_posix }} + ref: main + if: inputs.ansible_test_targets != '' + + - name: Checkout kubevirt.core repository + uses: actions/checkout@v3 + with: + path: ${{ env.source }} + fetch-depth: "0" + if: inputs.ansible_test_targets != '' + + - name: install kubernetes.core collection + uses: ansible-network/github_actions/.github/actions/build_install_collection@main + with: + install_python_dependencies: true + source_path: ${{ env.core }} + if: inputs.ansible_test_targets != '' + + - name: install cloud.common collection + uses: ansible-network/github_actions/.github/actions/build_install_collection@main + with: + install_python_dependencies: true + source_path: ${{ env.cloud_common }} + if: inputs.ansible_test_targets != '' + + - name: install ansible.posix collection + uses: ansible-network/github_actions/.github/actions/build_install_collection@main + with: + install_python_dependencies: true + source_path: ${{ env.ansible_posix }} + if: inputs.ansible_test_targets != '' + + - name: install kubevirt.core collection + id: install-collection + uses: ansible-network/github_actions/.github/actions/build_install_collection@main + with: + install_python_dependencies: true + source_path: ${{ env.source }} + if: inputs.ansible_test_targets != '' + + - name: install kind / kubectl + uses: helm/kind-action@v1.8.0 + with: + install_only: true + version: v0.20.0 + kubectl_version: v1.27.3 + if: inputs.ansible_test_targets != '' + + - name: deploy kubevirt + if: inputs.ansible_test_targets != '' + run: >- + ${{ env.source }}/hack/e2e-setup.sh \ + -v \ + --configure-inotify-limits \ + --configure-secondary-network \ + --deploy-kubevirt \ + --deploy-kubevirt-cdi \ + --deploy-kubevirt-common-instancetypes \ + --deploy-cnao \ + --create-cluster \ + --create-nad + shell: bash + env: + CLUSTER_NAME: kv-testing + KIND: kind + KUBECTL: kubectl + + - name: Run integration tests + uses: ansible-network/github_actions/.github/actions/ansible_test_integration@main + with: + collection_path: ${{ steps.install-collection.outputs.collection_path }} + python_version: ${{ matrix.python-version }} + ansible_version: ${{ matrix.ansible-version }} + ansible_test_targets: ${{ matrix.test-target }} + if: inputs.ansible_test_targets != '' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 11a6dc1..c880168 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -66,6 +66,8 @@ jobs: changelog_release: true generate_docs: false token: ${{ secrets.GITHUB_TOKEN }} + bot_email: kubevirtbot@redhat.com + bot_account: kubevirt-bot - name: Publish collection env: diff --git a/changelogs/config.yaml b/changelogs/config.yaml index d9c7f42..d8e3e16 100644 --- a/changelogs/config.yaml +++ b/changelogs/config.yaml @@ -9,21 +9,21 @@ notesdir: fragments prelude_section_name: release_summary prelude_section_title: Release Summary sections: -- - major_changes - - Major Changes -- - minor_changes - - Minor Changes -- - breaking_changes - - Breaking Changes / Porting Guide -- - deprecated_features - - Deprecated Features -- - removed_features - - Removed Features (previously deprecated) -- - security_fixes - - Security Fixes -- - bugfixes - - Bugfixes -- - known_issues - - Known Issues + - - major_changes + - Major Changes + - - minor_changes + - Minor Changes + - - breaking_changes + - Breaking Changes / Porting Guide + - - deprecated_features + - Deprecated Features + - - removed_features + - Removed Features (previously deprecated) + - - security_fixes + - Security Fixes + - - bugfixes + - Bugfixes + - - known_issues + - Known Issues title: KubeVirt Collection for Ansible trivial_section_name: trivial diff --git a/docs/index.rst b/docs/index.rst index 8f8e852..2d9da6d 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,7 +1,7 @@ -.. Red Hat kubevirt core Ansible Collection documentation main file +.. Red Hat kubevirt.core Ansible Collection documentation main file -Welcome to Kubevirt Collection documentation -======================================= +Welcome to kubevirt.core Collection documentation +================================================= .. toctree:: :maxdepth: 2 diff --git a/examples/play-create-dv.yml b/examples/play-create-dv.yml index 7e78c7f..ca779ba 100644 --- a/examples/play-create-dv.yml +++ b/examples/play-create-dv.yml @@ -1,4 +1,5 @@ -- hosts: localhost +- name: Playbook creating a virtual machine with data volume + hosts: localhost tasks: - name: Create VM kubevirt.core.kubevirt_vm: @@ -20,7 +21,7 @@ url: docker://quay.io/containerdisks/fedora:latest storage: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 5Gi @@ -28,14 +29,14 @@ domain: devices: {} volumes: - - dataVolume: - name: testdv - name: datavolume - - cloudInitNoCloud: - userData: |- - #cloud-config - # The default username is: fedora - ssh_authorized_keys: - - ssh-ed25519 AAAA... - name: cloudinit + - dataVolume: + name: testdv + name: datavolume + - cloudInitNoCloud: + userData: |- + #cloud-config + # The default username is: fedora + ssh_authorized_keys: + - ssh-ed25519 AAAA... + name: cloudinit wait: yes diff --git a/examples/play-create-min.yml b/examples/play-create-min.yml index e5c7a93..076353a 100644 --- a/examples/play-create-min.yml +++ b/examples/play-create-min.yml @@ -1,4 +1,5 @@ -- hosts: localhost +- name: Playbook instantiating a virtual machine + hosts: localhost tasks: - name: Create VM kubevirt.core.kubevirt_vm: diff --git a/examples/play-create.yml b/examples/play-create.yml index ba24fe4..9d09785 100644 --- a/examples/play-create.yml +++ b/examples/play-create.yml @@ -1,4 +1,5 @@ -- hosts: localhost +- name: Playbook creating a virtual machine with multus network + hosts: localhost tasks: - name: Create VM kubevirt.core.kubevirt_vm: @@ -15,25 +16,25 @@ domain: devices: interfaces: - - name: default - masquerade: {} - - name: bridge-network - bridge: {} + - name: default + masquerade: {} + - name: bridge-network + bridge: {} networks: - - name: default - pod: {} - - name: bridge-network - multus: - networkName: kindexgw + - name: default + pod: {} + - name: bridge-network + multus: + networkName: kindexgw volumes: - - containerDisk: - image: quay.io/containerdisks/fedora:latest - name: containerdisk - - cloudInitNoCloud: - userData: |- - #cloud-config - # The default username is: fedora - ssh_authorized_keys: - - ssh-ed25519 AAAA... - name: cloudinit + - containerDisk: + image: quay.io/containerdisks/fedora:latest + name: containerdisk + - cloudInitNoCloud: + userData: |- + #cloud-config + # The default username is: fedora + ssh_authorized_keys: + - ssh-ed25519 AAAA... + name: cloudinit wait: yes diff --git a/examples/play-delete-dv.yml b/examples/play-delete-dv.yml index 60fce20..8f045e3 100644 --- a/examples/play-delete-dv.yml +++ b/examples/play-delete-dv.yml @@ -1,4 +1,5 @@ -- hosts: localhost +- name: Playbook terminating a virtual machine with data volume + hosts: localhost tasks: - name: Delete VM kubevirt.core.kubevirt_vm: diff --git a/examples/play-delete.yml b/examples/play-delete.yml index dc89332..e4b6059 100644 --- a/examples/play-delete.yml +++ b/examples/play-delete.yml @@ -1,4 +1,5 @@ -- hosts: localhost +- name: Playbook terminating a virtual machine + hosts: localhost tasks: - name: Delete VM kubevirt.core.kubevirt_vm: diff --git a/examples/services.kubevirt.yml b/examples/services.kubevirt.yml index fcf92ad..10ad9e0 100644 --- a/examples/services.kubevirt.yml +++ b/examples/services.kubevirt.yml @@ -2,4 +2,4 @@ plugin: kubevirt.core.kubevirt connections: - namespaces: - default - use_service: yes \ No newline at end of file + use_service: yes diff --git a/galaxy.yml b/galaxy.yml index e1e3a2d..740709b 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,5 +1,3 @@ -# See https://docs.ansible.com/ansible/latest/dev_guide/collections_galaxy_meta.html - namespace: kubevirt name: core version: "0.1.0" @@ -7,12 +5,10 @@ readme: README.md authors: - KubeVirt Project (kubevirt.io) dependencies: - kubernetes.core: '>=2.0.0' + kubernetes.core: '>=2.0.0' description: Lean Ansible bindings for KubeVirt license_file: LICENSE tags: -# tags so people can search for collections https://galaxy.ansible.com/search -# tags are all lower-case, no spaces, no dashes. - api - k8s - kubernetes @@ -21,7 +17,7 @@ tags: - cloud - infrastructure repository: https://github.com/kubevirt/kubevirt.core -documentation: https://github.com/kubevirt/kubevirt.core/tree/main/docs +documentation: https://kubevirt.github.io/kubevirt.core homepage: https://kubevirt.io issues: https://github.com/kubevirt/kubevirt.core/issues build_ignore: diff --git a/tests/integration/targets/inventory_kubevirt/playbook.yml b/tests/integration/targets/inventory_kubevirt/playbook.yml new file mode 100644 index 0000000..3835e69 --- /dev/null +++ b/tests/integration/targets/inventory_kubevirt/playbook.yml @@ -0,0 +1,62 @@ +- name: Create VM + connection: local + gather_facts: false + hosts: localhost + tasks: + - name: Create a VirtualMachine + kubevirt.core.kubevirt_vm: + state: present + name: testvm + namespace: default + labels: + app: test + wait: yes + wait_timeout: 600 + spec: + domain: + cpu: + sockets: 1 + memory: + guest: 256Mi + devices: + interfaces: + - name: default + masquerade: {} + - name: bridge-network + bridge: {} + networks: + - name: default + pod: {} + - name: bridge-network + multus: + networkName: kindexgw + volumes: + - containerDisk: + image: quay.io/containerdisks/fedora:latest + name: containerdisk + - name: Create a 2nd VirtualMachine + kubevirt.core.kubevirt_vm: + state: present + name: testvm2 + namespace: default + labels: + foo: bar + wait: yes + wait_timeout: 600 + spec: + domain: + cpu: + sockets: 1 + memory: + guest: 256Mi + devices: + interfaces: + - name: default + masquerade: {} + networks: + - name: default + pod: {} + volumes: + - containerDisk: + image: quay.io/containerdisks/fedora:latest + name: containerdisk diff --git a/tests/integration/targets/inventory_kubevirt/runme.sh b/tests/integration/targets/inventory_kubevirt/runme.sh index 4233d3c..93df0e0 100755 --- a/tests/integration/targets/inventory_kubevirt/runme.sh +++ b/tests/integration/targets/inventory_kubevirt/runme.sh @@ -1,59 +1,27 @@ #!/usr/bin/env bash - set -eux +set -o pipefail -source virtualenv.sh -pip install kubernetes PyYAML jsonpatch Jinja2 +export ANSIBLE_ROLES_PATH="../" -./server.py & +USER_CREDENTIALS_DIR=$(pwd) +export USER_CREDENTIALS_DIR -cleanup() { - kill -9 "$(jobs -p)" -} +{ +export ANSIBLE_CALLBACKS_ENABLED=profile_tasks +export ANSIBLE_INVENTORY_ENABLED=kubevirt.core.kubevirt,yaml +export ANSIBLE_PYTHON_INTERPRETER=auto_silent + +ansible-inventory -i test.kubevirt.yml -y --list --output empty.yml "$@" + +ansible-playbook playbook.yml "$@" -trap cleanup INT TERM EXIT - -# Fake auth file -mkdir -p ~/.kube/ -cat < ~/.kube/config -apiVersion: v1 -clusters: -- cluster: - insecure-skip-tls-verify: true - server: http://localhost:12345 - name: development -contexts: -- context: - cluster: development - user: developer - name: dev-frontend -current-context: dev-frontend -kind: Config -preferences: {} -users: -- name: developer - user: - token: ZDNg7LzSlp8a0u0fht_tRnPMTOjxqgJGCyi_iy0ecUw -EOF - -################################################# -# RUN THE PLUGIN -################################################# - -# run the plugin second -export ANSIBLE_INVENTORY_ENABLED=kubevirt.core.kubevirt - -cat << EOF > "$OUTPUT_DIR/test.kubevirt.yml" -plugin: kubevirt.core.kubevirt -connections: - - namespaces: - - default -EOF - -ansible-inventory -vvvv -i "$OUTPUT_DIR/test.kubevirt.yml" --list --output="$OUTPUT_DIR/plugin.out" - -################################################# -# DIFF THE RESULTS -################################################# - -diff "$(pwd)/test.out" "$OUTPUT_DIR/plugin.out" +ansible-inventory -i test.kubevirt.yml -y --list --output all.yml "$@" +ansible-inventory -i test.label.kubevirt.yml -y --list --output label.yml "$@" +ansible-inventory -i test.net.kubevirt.yml -y --list --output net.yml "$@" + +ansible-playbook verify.yml "$@" + +} || { + exit 1 +} diff --git a/tests/integration/targets/inventory_kubevirt/server.py b/tests/integration/targets/inventory_kubevirt/server.py deleted file mode 100755 index ef1478c..0000000 --- a/tests/integration/targets/inventory_kubevirt/server.py +++ /dev/null @@ -1,322 +0,0 @@ -#!/usr/bin/env python -from __future__ import absolute_import, division, print_function - -__metaclass__ = type - -import json -import os -from http import HTTPStatus -from http.server import HTTPServer -from http.server import SimpleHTTPRequestHandler -from threading import Thread -from urllib.parse import urlparse - - -class TestHandler(SimpleHTTPRequestHandler): - # Path handlers: - handlers = {} - - def log_message(self, format, *args): - """ - Empty method, so we don't mix output of HTTP server with tests - """ - - def do_GET(self): - params = urlparse(self.path) - - if params.path in self.handlers: - self.handlers[params.path](self) - else: - SimpleHTTPRequestHandler.do_GET(self) - - def do_POST(self): - params = urlparse(self.path) - - if params.path in self.handlers: - self.handlers[params.path](self) - else: - self.send_error(HTTPStatus.NOT_FOUND) - - -class TestServer: - # The host and port and path used by the embedded tests web server: - PORT = None - - # The embedded web server: - _httpd = None - # Thread for http server: - _thread = None - - def set_json_response(self, path, code, body): - def _handle_request(handler): - handler.send_response(code) - handler.send_header("Content-Type", "application/json") - handler.end_headers() - - data = json.dumps(body, ensure_ascii=False).encode("utf-8") - handler.wfile.write(data) - - TestHandler.handlers[path] = _handle_request - - def start_server(self, host="localhost"): - self._httpd = HTTPServer((host, 12345), TestHandler) - self._thread = Thread(target=self._httpd.serve_forever) - self._thread.start() - - def stop_server(self): - self._httpd.shutdown() - self._thread.join() - - -if __name__ == "__main__": - print(os.getpid()) - server = TestServer() - server.start_server() - server.set_json_response(path="/version", code=200, body={}) - server.set_json_response( - path="/api", - code=200, - body={ - "kind": "APIVersions", - "versions": ["v1"], - "serverAddressByClientCIDRs": [ - {"clientCIDR": "0.0.0.0/0", "serverAddress": "localhost:12345"} - ], - }, - ) - server.set_json_response( - path="/api/v1", - code=200, - body={ - "kind": "APIResourceList", - "groupVersion": "v1", - "resources": [ - { - "name": "services", - "singularName": "service", - "namespaced": True, - "kind": "Service", - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update", - "watch", - ], - "shortNames": ["svc"], - } - ], - }, - ) - server.set_json_response( - path="/api/v1/namespaces/default/services", - code=200, - body={ - "kind": "ServiceList", - "groupVersion": "v1", - "items": [], - }, - ) - server.set_json_response( - path="/apis", - code=200, - body={ - "kind": "APIGroupList", - "apiVersion": "v1", - "groups": [ - { - "name": "kubevirt.io", - "versions": [{"groupVersion": "kubevirt.io/v1", "version": "v1"}], - "preferredVersion": { - "groupVersion": "kubevirt.io/v1", - "version": "v1", - }, - } - ], - }, - ) - server.set_json_response( - path="/apis/kubevirt.io/v1", - code=200, - body={ - "kind": "APIResourceList", - "apiVersion": "v1", - "groupVersion": "kubevirt.io/v1", - "resources": [ - { - "name": "virtualmachineinstances", - "singularName": "virtualmachineinstance", - "namespaced": True, - "kind": "VirtualMachineInstance", - "verbs": [ - "delete", - "deletecollection", - "get", - "list", - "patch", - "create", - "update", - "watch", - ], - "shortNames": ["vmi", "vmis"], - } - ], - }, - ) - server.set_json_response( - path="/apis/kubevirt.io/v1/namespaces/default/virtualmachineinstances", - code=200, - body={ - "apiVersion": "v1", - "items": [ - { - "apiVersion": "kubevirt.io/v1", - "kind": "VirtualMachineInstance", - "metadata": { - "annotations": { - "kubevirt.io/latest-observed-api-version": "v1", - "kubevirt.io/storage-observed-api-version": "v1alpha3", - }, - "creationTimestamp": "2022-09-14T13:43:36Z", - "finalizers": [ - "kubevirt.io/virtualMachineControllerFinalize", - "foregroundDeleteVirtualMachine", - ], - "generation": 9, - "labels": { - "kubevirt.io/nodeName": "node01", - "kubevirt.io/vm": "vm-cirros", - }, - "name": "vm-cirros", - "namespace": "default", - "ownerReferences": [ - { - "apiVersion": "kubevirt.io/v1", - "blockOwnerDeletion": True, - "controller": True, - "kind": "VirtualMachine", - "name": "vm-cirros", - "uid": "4d1b1438-91ba-4c75-a211-566fc50a06f5", - } - ], - "resourceVersion": "5387", - "uid": "7b3a8d94-bd7e-4c14-818a-89228172e4f1", - }, - "spec": { - "domain": { - "cpu": { - "cores": 1, - "model": "host-model", - "sockets": 1, - "threads": 1, - }, - "devices": { - "disks": [ - { - "disk": {"bus": "virtio"}, - "name": "containerdisk", - }, - { - "disk": {"bus": "virtio"}, - "name": "cloudinitdisk", - }, - ], - "interfaces": [{"bridge": {}, "name": "default"}], - }, - "features": {"acpi": {"enabled": True}}, - "firmware": { - "uuid": "0d2a2043-41c0-59c3-9b17-025022203668" - }, - "machine": {"type": "q35"}, - "resources": {"requests": {"memory": "128Mi"}}, - }, - "networks": [{"name": "default", "pod": {}}], - "terminationGracePeriodSeconds": 0, - "volumes": [ - { - "containerDisk": { - "image": "registry:5000/kubevirt/cirros-container-disk-demo:devel", - "imagePullPolicy": "IfNotPresent", - }, - "name": "containerdisk", - }, - { - "cloudInitNoCloud": { - "userData": "#!/bin/sh\n\necho 'printed from cloud-init userdata'\n" - }, - "name": "cloudinitdisk", - }, - ], - }, - "status": { - "activePods": { - "a9a6c31b-8574-46f9-8bec-70ff091c3d97": "node01" - }, - "conditions": [ - { - "lastProbeTime": None, - "lastTransitionTime": "2022-09-14T13:43:39Z", - "status": "True", - "type": "Ready", - }, - { - "lastProbeTime": None, - "lastTransitionTime": None, - "message": "cannot migrate VMI which does not use masquerade to connect to the pod network", - "reason": "InterfaceNotLiveMigratable", - "status": "False", - "type": "LiveMigratable", - }, - ], - "guestOSInfo": {}, - "interfaces": [ - { - "infoSource": "domain", - "ipAddress": "10.244.196.152", - "ipAddresses": ["10.244.196.152", "fd10:244::c497"], - "mac": "96:13:92:4f:05:d3", - "name": "default", - "queueCount": 1, - } - ], - "launcherContainerImageVersion": - "registry:5000/kubevirt/virt-launcher@sha256:5c1474d240488c9a8e6e6e48b2ad446113744353b4cd2464baee3550e6b1829d", - "migrationMethod": "BlockMigration", - "migrationTransport": "Unix", - "nodeName": "node01", - "phase": "Running", - "phaseTransitionTimestamps": [ - { - "phase": "Pending", - "phaseTransitionTimestamp": "2022-09-14T13:43:36Z", - }, - { - "phase": "Scheduling", - "phaseTransitionTimestamp": "2022-09-14T13:43:36Z", - }, - { - "phase": "Scheduled", - "phaseTransitionTimestamp": "2022-09-14T13:43:39Z", - }, - { - "phase": "Running", - "phaseTransitionTimestamp": "2022-09-14T13:43:40Z", - }, - ], - "qosClass": "Burstable", - "runtimeUser": 0, - "virtualMachineRevisionName": "revision-start-vm-4d1b1438-91ba-4c75-a211-566fc50a06f5-9", - "volumeStatus": [ - {"name": "cloudinitdisk", "size": 1048576, "target": "vdb"}, - {"name": "containerdisk", "target": "vda"}, - ], - }, - } - ], - "kind": "List", - "metadata": {"resourceVersion": "", "selfLink": ""}, - }, - ) diff --git a/tests/integration/targets/inventory_kubevirt/test.kubevirt.yml b/tests/integration/targets/inventory_kubevirt/test.kubevirt.yml new file mode 100644 index 0000000..e9c2806 --- /dev/null +++ b/tests/integration/targets/inventory_kubevirt/test.kubevirt.yml @@ -0,0 +1,4 @@ +plugin: kubevirt.core.kubevirt +connections: + - namespaces: + - default diff --git a/tests/integration/targets/inventory_kubevirt/test.label.kubevirt.yml b/tests/integration/targets/inventory_kubevirt/test.label.kubevirt.yml new file mode 100644 index 0000000..4d4fba2 --- /dev/null +++ b/tests/integration/targets/inventory_kubevirt/test.label.kubevirt.yml @@ -0,0 +1,5 @@ +plugin: kubevirt.core.kubevirt +connections: + - namespaces: + - default + label_selector: app=test diff --git a/tests/integration/targets/inventory_kubevirt/test.net.kubevirt.yml b/tests/integration/targets/inventory_kubevirt/test.net.kubevirt.yml new file mode 100644 index 0000000..828b2fb --- /dev/null +++ b/tests/integration/targets/inventory_kubevirt/test.net.kubevirt.yml @@ -0,0 +1,5 @@ +plugin: kubevirt.core.kubevirt +connections: + - namespaces: + - default + network_name: bridge-network diff --git a/tests/integration/targets/inventory_kubevirt/test.out b/tests/integration/targets/inventory_kubevirt/test.out deleted file mode 100644 index 943a82e..0000000 --- a/tests/integration/targets/inventory_kubevirt/test.out +++ /dev/null @@ -1,124 +0,0 @@ -{ - "_meta": { - "hostvars": { - "default-vm-cirros": { - "annotations": { - "kubevirt.io/latest-observed-api-version": "v1", - "kubevirt.io/storage-observed-api-version": "v1alpha3" - }, - "ansible_connection": "ssh", - "ansible_host": "10.244.196.152", - "cluster_name": null, - "labels": { - "kubevirt.io/nodeName": "node01", - "kubevirt.io/vm": "vm-cirros" - }, - "object_type": "vmi", - "resource_version": "5387", - "uid": "7b3a8d94-bd7e-4c14-818a-89228172e4f1", - "vmi_active_pods": { - "a9a6c31b-8574-46f9-8bec-70ff091c3d97": "node01" - }, - "vmi_conditions": [ - { - "lastProbeTime": null, - "lastTransitionTime": "2022-09-14T13:43:39Z", - "status": "True", - "type": "Ready" - }, - { - "lastProbeTime": null, - "lastTransitionTime": null, - "message": "cannot migrate VMI which does not use masquerade to connect to the pod network", - "reason": "InterfaceNotLiveMigratable", - "status": "False", - "type": "LiveMigratable" - } - ], - "vmi_guest_os_info": {}, - "vmi_interfaces": [ - { - "infoSource": "domain", - "ipAddress": "10.244.196.152", - "ipAddresses": [ - "10.244.196.152", - "fd10:244::c497" - ], - "mac": "96:13:92:4f:05:d3", - "name": "default", - "queueCount": 1 - } - ], - "vmi_launcher_container_image_version": "registry:5000/kubevirt/virt-launcher@sha256:5c1474d240488c9a8e6e6e48b2ad446113744353b4cd2464baee3550e6b1829d", - "vmi_migration_method": "BlockMigration", - "vmi_migration_transport": "Unix", - "vmi_node_name": "node01", - "vmi_phase": "Running", - "vmi_phase_transition_timestamps": [ - { - "phase": "Pending", - "phaseTransitionTimestamp": "2022-09-14T13:43:36Z" - }, - { - "phase": "Scheduling", - "phaseTransitionTimestamp": "2022-09-14T13:43:36Z" - }, - { - "phase": "Scheduled", - "phaseTransitionTimestamp": "2022-09-14T13:43:39Z" - }, - { - "phase": "Running", - "phaseTransitionTimestamp": "2022-09-14T13:43:40Z" - } - ], - "vmi_qos_class": "Burstable", - "vmi_virtual_machine_revision_name": "revision-start-vm-4d1b1438-91ba-4c75-a211-566fc50a06f5-9", - "vmi_volume_status": [ - { - "name": "cloudinitdisk", - "size": 1048576, - "target": "vdb" - }, - { - "name": "containerdisk", - "target": "vda" - } - ] - } - } - }, - "all": { - "children": [ - "ungrouped", - "localhost_12345", - "label_kubevirt_io_nodeName_node01", - "label_kubevirt_io_vm_vm_cirros" - ] - }, - "label_kubevirt_io_nodeName_node01": { - "hosts": [ - "default-vm-cirros" - ] - }, - "label_kubevirt_io_vm_vm_cirros": { - "hosts": [ - "default-vm-cirros" - ] - }, - "localhost_12345": { - "children": [ - "namespace_default" - ] - }, - "namespace_default": { - "children": [ - "namespace_default_vmis" - ] - }, - "namespace_default_vmis": { - "hosts": [ - "default-vm-cirros" - ] - } -} \ No newline at end of file diff --git a/tests/integration/targets/inventory_kubevirt/verify.yml b/tests/integration/targets/inventory_kubevirt/verify.yml new file mode 100644 index 0000000..022d2d8 --- /dev/null +++ b/tests/integration/targets/inventory_kubevirt/verify.yml @@ -0,0 +1,35 @@ +--- +- name: Verify inventory + connection: local + gather_facts: false + hosts: localhost + tasks: + - name: Read empty inventory + ansible.builtin.include_vars: + file: empty.yml + name: inv_empty + - name: Read inventory after vm creation + ansible.builtin.include_vars: + file: all.yml + name: inv_all + - name: Assert two instances with different labels + ansible.builtin.assert: + that: + - inv_all['all']['children']['label_app_test']['hosts'] | length == 1 + - inv_all['all']['children']['label_foo_bar']['hosts'] | length == 1 + - name: Read filtered inventory + ansible.builtin.include_vars: + file: label.yml + name: inv_label + - name: Assert one instance with selected label + ansible.builtin.assert: + that: + - inv_label['all']['children']['label_app_test']['hosts'] | length == 1 + - name: Read filtered inventory + ansible.builtin.include_vars: + file: net.yml + name: inv_net + - name: Assert one instance with selected network + ansible.builtin.assert: + that: + - inv_net['all']['children']['label_app_test']['hosts'] | length == 1 diff --git a/tests/integration/targets/kubevirt_vm/playbook.yml b/tests/integration/targets/kubevirt_vm/playbook.yml new file mode 100644 index 0000000..950c490 --- /dev/null +++ b/tests/integration/targets/kubevirt_vm/playbook.yml @@ -0,0 +1,43 @@ +--- +- name: Create VM + connection: local + gather_facts: false + hosts: localhost + tasks: + - name: Create a VirtualMachine + kubevirt.core.kubevirt_vm: + state: present + name: testvm3 + namespace: default + labels: + app: test + wait: true + wait_timeout: 600 + spec: + domain: + cpu: + sockets: 1 + memory: + guest: 1536Mi + devices: + interfaces: + - name: default + masquerade: {} + - name: bridge-network + bridge: {} + networks: + - name: default + pod: {} + - name: bridge-network + multus: + networkName: kindexgw + volumes: + - containerDisk: + image: quay.io/containerdisks/centos-stream:9 + name: containerdisk + - cloudInitNoCloud: + userData: |- + #cloud-config + ssh_authorized_keys: + - {{ lookup('file', 'pub_key') }} + name: cloudinit diff --git a/tests/integration/targets/kubevirt_vm/runme.sh b/tests/integration/targets/kubevirt_vm/runme.sh new file mode 100755 index 0000000..b879f4f --- /dev/null +++ b/tests/integration/targets/kubevirt_vm/runme.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -eux +set -o pipefail + +{ +export ANSIBLE_CALLBACKS_ENABLED=profile_tasks +export ANSIBLE_INVENTORY_ENABLED=kubevirt.core.kubevirt,yaml + +[ -d files ] || mkdir files +[ -f files/priv_key ] || (ssh-keygen -t ed25519 -C test@test -f files/priv_key ; ssh-keygen -y -f files/priv_key > files/pub_key) + +ansible-playbook playbook.yml "$@" + +ansible-inventory -i test.kubevirt.yml -y --list "$@" + +ansible-playbook verify.yml -i test.kubevirt.yml --private-key=files/priv_key "$@" + +rm "$HOME/.ssh/known_hosts" +} || { + exit 1 +} diff --git a/tests/integration/targets/kubevirt_vm/test.kubevirt.yml b/tests/integration/targets/kubevirt_vm/test.kubevirt.yml new file mode 100644 index 0000000..828b2fb --- /dev/null +++ b/tests/integration/targets/kubevirt_vm/test.kubevirt.yml @@ -0,0 +1,5 @@ +plugin: kubevirt.core.kubevirt +connections: + - namespaces: + - default + network_name: bridge-network diff --git a/tests/integration/targets/kubevirt_vm/verify.yml b/tests/integration/targets/kubevirt_vm/verify.yml new file mode 100644 index 0000000..5332add --- /dev/null +++ b/tests/integration/targets/kubevirt_vm/verify.yml @@ -0,0 +1,69 @@ +--- +- name: Wait for ssh + connection: local + gather_facts: false + hosts: localhost + tasks: + - name: Wait up to 900 seconds for port 22 to become open + ansible.builtin.wait_for: + port: 22 + host: "{{ hostvars['default-testvm3'].ansible_host }}" + delay: 30 + timeout: 900 + +- name: Connect to VM + gather_facts: true + hosts: default-testvm3 + remote_user: centos + vars: + ansible_python_interpreter: /usr/bin/python3 + tasks: + - name: Print out virtual machine facts + ansible.builtin.debug: + var: ansible_facts + +- name: Verify creation with existing VM + connection: local + gather_facts: false + hosts: localhost + tasks: + - name: Create a VirtualMachine + kubevirt.core.kubevirt_vm: + state: present + name: testvm3 + namespace: default + labels: + app: test + register: recreate + - name: Assert module reported no changes + ansible.builtin.assert: + that: + - not recreate.changed + +- name: Delete VM + connection: local + gather_facts: false + hosts: localhost + tasks: + - name: Delete a VirtualMachine + kubevirt.core.kubevirt_vm: + state: absent + name: testvm3 + namespace: default + wait: true + +- name: Verify VM deletion + connection: local + gather_facts: false + hosts: localhost + tasks: + - name: Delete a VirtualMachine + kubevirt.core.kubevirt_vm: + state: absent + name: testvm3 + namespace: default + register: delete + - name: Assert module reported no changes + ansible.builtin.assert: + that: + - not delete.changed