Skip to content

Ansible

This page provides example Ansible playbooks for managing virtual machines on OpenShift Virtualization using the kubevirt.core collection. It covers deploying VMs, uploading ISO images, adjusting VM resources, and running the playbooks with both ansible-navigator and Ansible Automation Platform.

Note

community.kubevirt is UNMAINTAINED please use kubevirt.core

Playbook examples

Deploy VM
curl -L -O https://examples.openshift.pub/kubevirt/ansible/playbook-vm.yaml
---
# Execution
# cp -v $KUBECONFIG .
# /Users/rbohne/.kube/.switch_tmp/config.2962012707.tmp -> ./config.2962012707.tmp
# export K8S_AUTH_KUBECONFIG=$(basename $KUBECONFIG)
# ansible-navigator run playbook-vm.yaml

- hosts: localhost
  connection: local
  gather_facts: false
  vars:
    namespace: rbohne-kubevirt-ansible
  tasks:

    - name: Deploy VM
      kubevirt.core.kubevirt_vm:
        state: present
        run_strategy: Always # default
        wait: true
        name: rhel9
        namespace: "{{ namespace }}"

        data_volume_templates:
          - metadata:
              name: rhel9-root
            spec:
              storage:
                accessModes:
                  - ReadWriteMany
                resources:
                  requests:
                    storage: 30Gi
              sourceRef:
                kind: DataSource
                name: rhel9
                namespace: openshift-virtualization-os-images
        spec:
          volumes:
            - name: root
              dataVolume:
                name: rhel9-root
          networks:
            - name: coe
              multus:
                networkName: coe-bridge
          domain:
            cpu:
              cores: 2
            memory:
              guest: 4Gi
            resources:
              requests:
                memory: 4Gi
            devices:
              disks:
                - name: root
                  bootOrder: 1
                  disk:
                    bus: virtio
              interfaces:
                - bridge: {}
                  model: virtio
                  name: coe

Adjust VM resources
curl -L -O https://examples.openshift.pub/kubevirt/ansible/playbook-adjust-vm.yaml
---
# Execution
# cp -v $KUBECONFIG .
# /Users/rbohne/.kube/.switch_tmp/config.2962012707.tmp -> ./config.2962012707.tmp
# export K8S_AUTH_KUBECONFIG=$(basename $KUBECONFIG)
# ansible-navigator run playbook-adjust-vm.yaml

- hosts: localhost
  connection: local
  gather_facts: false
  vars:
    namespace: rbohne-kubevirt-ansible
    new_memory: 16Gi

  tasks:

    - name: Adjust Memory of VM
      kubevirt.core.kubevirt_vm:
        state: present
        wait: true
        name: rhel9
        namespace: "{{ namespace }}"

        spec:
          domain:
            memory:
              guest: "{{ new_memory }}"

Upload an ISO
curl -L -O https://examples.openshift.pub/kubevirt/ansible/playbook-upload.yaml
---
- hosts: localhost
  connection: local
  gather_facts: false
  vars:
    upload_host: https://cdi-uploadproxy-openshift-cnv.apps.isar.coe.muc.redhat.com
    namespace: rbohne-virt-roadshow
  tasks:

    # https://github.com/kubevirt/containerized-data-importer/blob/main/doc/upload.md

    - name: Create DataVolume
      # register: my_var_with_return_value
      kubernetes.core.k8s:
        state: present
        wait: yes
        wait_condition:
          type: Running
          status: True
          reason: Pod is running
        definition:
          apiVersion: cdi.kubevirt.io/v1beta1
          kind: DataVolume
          metadata:
            name: customer-iso
            namespace: "{{ namespace }}"
          spec:
            source:
                upload: {}
            pvc:
              accessModes:
                - ReadWriteMany
              storageClassName: ocs-storagecluster-cephfs
              resources:
                requests:
                  storage: 2Gi

    - name: Upload token
      register: my_var_with_return_value
      kubernetes.core.k8s:
        state: present
        definition:
          apiVersion: upload.cdi.kubevirt.io/v1beta1
          kind: UploadTokenRequest
          metadata:
            name: customer-iso-upload-token
            namespace: "{{ namespace }}"
          spec:
            pvcName: customer-iso

# curl -v --insecure -H "Authorization: Bearer $TOKEN" --data-binary @tests/images/cirros-qcow2.img https://$(minikube ip):31001/v1beta1/upload
#
    # - name: Show token
    #   debug:
    #     msg: "curl -v --insecure -H 'Authorization: Bearer  {{ my_var_with_return_value.result.status.token }}' --data-binary @/var/home/rbohne/Downloads/beryllium-1-i386.hybrid.iso https://{{ upload_host }}/v1beta1/upload "

    - name: Upload beryllium-1-i386.hybrid.iso
      ansible.builtin.uri:
        url: "{{ upload_host }}/v1beta1/upload"
        method: POST
        validate_certs: false
        headers:
          Authorization: "Bearer  {{ my_var_with_return_value.result.status.token }}"
        src: /home/rbohne/virt-ansible-demo/boron-1-240124-i386.hybrid.iso

Run the playbook with ansible-navigator

The playbooks run inside an Ansible execution environment container. Copy your kubeconfig into the project directory so it is available inside the container:

Clone and run
1
2
3
4
5
git clone https://github.com/openshift-examples/kubevirt-ansible.git
cd kubevirt-ansible
cp -v $KUBECONFIG .
export K8S_AUTH_KUBECONFIG=$(basename $KUBECONFIG)
ansible-navigator run playbook-vm.yaml

Run the playbook with Ansible Automation Platform

The playbooks can also be run from Ansible Automation Platform (AAP). Create a service account on the target OpenShift cluster so AAP can authenticate and manage VMs.

Create service account for AAP

Create service account and token
% oc create sa aap
serviceaccount/aap created
% oc create token aap
% oc policy add-role-to-user admin -z aap
clusterrole.rbac.authorization.k8s.io/admin added: "aap"
% oc policy add-role-to-user kubevirt.io:admin -z aap
clusterrole.rbac.authorization.k8s.io/kubevirt.io:admin added: "aap"
% oc create -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: aap-token
  annotations:
    kubernetes.io/service-account.name: aap
type: kubernetes.io/service-account-token
EOF

Ansible Automation Platform configuration

Once the service account is created, configure AAP:

  1. Add a Credential of type OpenShift or Kubernetes API Bearer Token using the service account token and the cluster API URL
  2. Add a Project pointing to the kubevirt-ansible git repository
  3. Add an Execution Environment referencing the custom execution environment image (see below)
  4. Create a Job Template that combines the credential, project, and execution environment, then launch it

Execution environment configuration

The execution environment bundles all required Ansible collections and Python dependencies into a container image so playbooks run consistently across environments.

ansible-navigator.yaml
---
ansible-navigator:
  execution-environment:
    image: quay.io/openshift-examples/kubevirt-ansible-ee:202607301716
    environment-variables:
      pass:
        - KUBECONFIG
        - K8S_AUTH_KUBECONFIG
  logging:
    level: info
  mode: stdout
  playbook-artifact:
    enable: true
    save-as: /tmp/example-openshift-kubevirt-{playbook_name}-artifact-{time_stamp}.json
execution-environment.yml (AAP base image)
---
version: 3

options:
  package_manager_path: /usr/bin/microdnf

images:
  base_image:
    name: 'registry.redhat.io/ansible-automation-platform-27/ee-supported-rhel9:1783923018'

additional_build_steps:
  # prepend_builder:
  #   - ENV PKGMGR_OPTS="--nodocs --setopt=install_weak_deps=0 --setopt=rhocp-4.20-for-rhel-9-x86_64-rpms.enabled=true"
  # prepend_final:
  #   - ENV PKGMGR_OPTS="--nodocs --setopt=install_weak_deps=0 --setopt=rhocp-4.20-for-rhel-9-x86_64-rpms.enabled=true"
  # append_final:
  #   # Example how to add a root CA to the execution environment
  #   - RUN curl https://certs.corp.redhat.com/certs/Current-IT-Root-CAs.pem
  #         -o /etc/pki/ca-trust/source/anchors/RedHat_Current-IT-Root-CAs.pem &&
  #         update-ca-trust

dependencies:
  ansible_core:
    package_pip: ansible-core==2.21.2
  ansible_runner:
    package_pip: ansible-runner>=2.4.3
  exclude:
    python:
      - systemd-python
  # python:
  #   - ovirt-engine-sdk-python 
  #   - six
  system:
  #   - nmstate
    - python3.12
    - python3.12-devel
    - python3-pip
  #   - python3-systemd
    - python3-wheel        # Fixes the 'legacy setup.py' warning
    - python3-setuptools   # Standardizes the build environment
  #   - libxml2-devel
  #   - libcurl-devel 
  galaxy:
    collections:
# ToDo: add version numbers!
      - name: community.general
      - name: community.kubernetes
      - name: redhat.openshift
      - name: kubernetes.core
      - name: ansible.posix
      - name: community.crypto
      - name: kubevirt.core
execution-environment-ubi.yml (UBI base image)
---
version: 3

images:
  base_image:
    name: registry.access.redhat.com/ubi9/ubi:latest

# additional_build_steps:
#   append_final:
#     - RUN curl https://certs.corp.redhat.com/certs/Current-IT-Root-CAs.pem
#           -o /etc/pki/ca-trust/source/anchors/RedHat_Current-IT-Root-CAs.pem &&
#           update-ca-trust

dependencies:
  ansible_core:
    package_pip: ansible-core
  ansible_runner:
    package_pip: ansible-runner
  system:
    - openssh-clients
    - sshpass
  python:
    # Import for community.general.json_query
    - jmespath
  galaxy:
    collections:
      - name: community.general
      - name: community.kubernetes
      - name: kubernetes.core
      - name: ansible.posix
      - name: community.crypto
      - name: kubevirt.core

How to build the execution environment

Two execution environment definitions are available: one based on the AAP supported EE image (execution-environment.yml) and one based on UBI 9 (execution-environment-ubi.yml). The examples below use the UBI variant.

1
2
3
podman login registry.redhat.io
export VERSION=$(date +%Y%m%d%H%M)
export IMAGE=quay.io/openshift-examples/kubevirt-ansible-ee:${VERSION}

Build on Linux/RHEL

Build on Linux/RHEL
1
2
3
4
5
6
ansible-builder build \
    --verbosity 3 \
    --file execution-environment-ubi.yml \
    --container-runtime podman \
    --tag ${IMAGE}
podman push ${IMAGE}

Multi-arch build on Mac OS

On Mac OS, ansible-builder build does not support multi-arch builds directly. Use ansible-builder create to generate the build context, then build with podman:

Multi-arch build on Mac OS
1
2
3
4
5
6
7
8
ansible-builder create \
    --file execution-environment-ubi.yml \
    --verbosity 3

podman build --platform linux/amd64,linux/arm64 \
   --manifest ${IMAGE} context/

podman manifest push ${IMAGE}

2026-07-30 2023-12-22