ci: integration tests

Signed-off-by: Guido Grazioli <ggraziol@redhat.com>
This commit is contained in:
Guido Grazioli
2023-07-27 14:50:08 +02:00
parent f5b8372a75
commit 198d885b8f
26 changed files with 626 additions and 703 deletions

35
.ansible-lint Normal file
View File

@@ -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

View File

@@ -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
- unit-source
with:
ansible_test_targets: >-
[
"kubevirt_vm",
"inventory_kubevirt"
]
name: "integration"
- 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 != ''
- 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:

View File

@@ -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

224
.github/workflows/integration.yml vendored Normal file
View File

@@ -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 != ''

View File

@@ -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:

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -1,4 +1,5 @@
- hosts: localhost
- name: Playbook instantiating a virtual machine
hosts: localhost
tasks:
- name: Create VM
kubevirt.core.kubevirt_vm:

View File

@@ -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

View File

@@ -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:

View File

@@ -1,4 +1,5 @@
- hosts: localhost
- name: Playbook terminating a virtual machine
hosts: localhost
tasks:
- name: Delete VM
kubevirt.core.kubevirt_vm:

View File

@@ -2,4 +2,4 @@ plugin: kubevirt.core.kubevirt
connections:
- namespaces:
- default
use_service: yes
use_service: yes

View File

@@ -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:

View File

@@ -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

View File

@@ -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 "$@"
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
}
trap cleanup INT TERM EXIT
# Fake auth file
mkdir -p ~/.kube/
cat <<EOF > ~/.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"

View File

@@ -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": ""},
},
)

View File

@@ -0,0 +1,4 @@
plugin: kubevirt.core.kubevirt
connections:
- namespaces:
- default

View File

@@ -0,0 +1,5 @@
plugin: kubevirt.core.kubevirt
connections:
- namespaces:
- default
label_selector: app=test

View File

@@ -0,0 +1,5 @@
plugin: kubevirt.core.kubevirt
connections:
- namespaces:
- default
network_name: bridge-network

View File

@@ -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"
]
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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
}

View File

@@ -0,0 +1,5 @@
plugin: kubevirt.core.kubevirt
connections:
- namespaces:
- default
network_name: bridge-network

View File

@@ -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