A Beaker hypervisor provider for KubeVirt, enabling automated acceptance testing of Puppet code using virtual machines running inside Kubernetes clusters.
- Deploy VMs using KubeVirt's
VirtualMachineobjects - Support for multiple image sources (PVC, ContainerDisk, DataVolume)
- Cloud-init configuration injection for user setup and SSH keys
- Multiple networking modes (port-forward, NodePort, Multus)
- Automatic VM lifecycle management (provision, test, cleanup)
- Integration with existing Beaker workflows
Add this line to your application's Gemfile:
gem 'beaker-kubevirt'And then execute:
bundle installOr install it yourself as:
gem install beaker-kubevirt- A Kubernetes cluster with KubeVirt installed
- Valid kubeconfig file with cluster access
- SSH public key for VM access
Configure your Beaker hosts file to use the KubeVirt hypervisor:
HOSTS:
centos-vm:
platform: el-8-x86_64
hypervisor: kubevirt
kubevirt_vm_image: docker://quay.io/kubevirt/fedora-cloud-container-disk-demo
kubevirt_network_mode: port-forward
kubevirt_ssh_key: ~/.ssh/id_rsa.pub
kubevirt_cpus: 2
kubevirt_memory: 4Gi
CONFIG:
# Global KubeVirt configuration
kubeconfig: <%= ENV.fetch('KUBECONFIG', '~/.kube/config') %>
kubecontext: my-context # optional
namespace: beaker-tests # required - namespace for all VMs
kubevirt_service_account: beaker-kubevirt-sa # optional - required for cross-namespace PVC cloning
ssh:
password: beaker
auth_methods: ['publickey', 'password']| Option | Description | Required | Default | Location |
|---|---|---|---|---|
kubeconfig |
Path to kubeconfig file | Yes | $KUBECONFIG or ~/.kube/config |
CONFIG (global) |
kubecontext |
Kubernetes context to use | No | Current context | CONFIG (global) |
namespace |
Kubernetes namespace for VMs | Yes | default |
CONFIG (global) |
kubevirt_service_account |
Service account for cross-namespace PVC cloning | No | default |
CONFIG (global) |
kubevirt_vm_image |
VM image specification | Yes | - | HOSTS (per-host) |
kubevirt_network_mode |
Networking mode | No | port-forward |
HOSTS (per-host) |
networks |
Custom network configuration | No | Auto-generated | HOSTS (per-host) |
kubevirt_ssh_key |
SSH public key path or content | Yes | Auto-detect from ~/.ssh/ |
HOSTS (per-host) |
kubevirt_cpus |
CPU cores for VM | No | 1 |
HOSTS (per-host) |
kubevirt_memory |
Memory for VM | No | 2Gi |
HOSTS (per-host) |
kubevirt_memory_overhead |
Extra memory added to the guest for the virt-launcher container memory limit. Raise this for Windows guests that OOMKill with the default. | No | 512Mi |
HOSTS (per-host), CONFIG |
kubevirt_memory_request |
Memory request for the VM pod. | No | Same as kubevirt_memory |
HOSTS (per-host), CONFIG |
kubevirt_disk_size |
Size of the root disk | No | 10Gi |
HOSTS (per-host) |
kubevirt_cloud_init |
Custom cloud-init YAML | No | Auto-generated | HOSTS (per-host) |
kubevirt_vm_ssh_port |
SSH port inside the VM | No | 22 |
HOSTS (per-host) |
kubevirt_readiness_probe_disabled |
Skip the VMI SSH readinessProbe. Default is false for pod-network modes and true for multus (where a probe from the virt-launcher netns typically can't reach a bridge-only guest). |
No | mode-dependent | HOSTS (per-host), CONFIG |
kubevirt_readiness_probe |
Probe tuning hash (snake_case keys): initial_delay_seconds (30), period_seconds (10), timeout_seconds (3), failure_threshold (60), success_threshold (1). The default failure budget (600s) accommodates slow Windows first-boots. When the probe is enabled, timeout is auto-raised to cover this budget. |
No | see description | HOSTS (per-host), CONFIG |
kubevirt_disable_virtio |
Disable virtio devices (for Windows compatibility). If set to true the disk bus will be set to sata and the network adapter will be model e1000 |
No | false |
HOSTS (per-host) |
Important: The namespace, kubeconfig, and kubecontext options must be specified in the global CONFIG section, not per-host. All VMs will be created in the same Kubernetes namespace.
Notes:
- Several per-host options support global fallbacks via
CONFIG(e.g.,kubevirt_cpus,kubevirt_memory,kubevirt_vm_ssh_port). - The
networkskey for Multus is intentionally unprefixed (usenetworks, notkubevirt_networks). - Long-running commands aren't killed by idle-timeout drops, even when output streams in only one direction (e.g., a Windows scanner running for many minutes). The
port-forwardproxy no longer enforces a client-side read-silence timeout (it relied on net-ssh keepalive packets that net-ssh suppresses while server output is flowing) and instead sends a WebSocket protocol ping every 60s to keep the upstream tunnel alive. net-ssh keepalive defaults are also tightened tokeepalive_interval: 60,keepalive_maxcount: 5— Beaker already enableskeepalive: true— which protectsmultusandnodeportmodes against NAT/conntrack timeouts. Override per-host underssh:if needed.
The kubevirt_vm_image option supports several formats:
- Container image:
docker://quay.io/kubevirt/fedora-cloud-container-disk-demooroci://quay.io/kubevirt/fedora-cloud-container-disk-demo - PVC reference:
pvc:my-vm-disk,my-vm-disk(uses current namespace), ornamespace/pvc-name(cross-namespace PVC) - DataVolume:
http://example.com/my-datavolume.imgorhttps://example.com/my-datavolume.imgNOTE: KubeVirt CDI must be installed in the cluster for DataVolume support.
When cloning PVCs from a different namespace than where the VMs run, you must configure a service account with appropriate RBAC permissions. This is required because the DataVolume controller needs authorization to read PVCs in the source namespace.
-
Create the service account and RBAC resources:
kubectl create serviceaccount beaker-kubevirt -n beaker-tests
Save the following RBAC configuration to
cluster-role.yaml:--- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: beaker-kubevirt:volumes:clone rules: - apiGroups: - cdi.kubevirt.io resources: - datavolumes/source verbs: - '*'
Then apply it:
kubectl apply -f cluster-role.yaml
Save the following RoleBinding configuration to
pvc-clone-rbac.yaml:--- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: beaker-kubevirt:volumes:clone-binding namespace: source-namespace roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: beaker-kubevirt:volumes:clone subjects: - kind: ServiceAccount name: beaker-kubevirt namespace: destination-namespace
Apply the RoleBinding (replace
source-namespaceanddestination-namespacewith your actual namespaces):kubectl apply -f pvc-clone-rbac.yaml
This creates a beaker-kubevirt service account in the beaker test namespace with permissions to update DataVolumes to indicate a clone source in the specified source namespace.
-
Configure beaker to use the service account:
CONFIG: namespace: beaker-tests kubevirt_service_account: beaker-kubevirt
-
Reference PVCs from other namespaces:
HOSTS: test-vm: kubevirt_vm_image: other-namespace/source-pvc-name
This configuration allows Beaker to create VMs that clone PVCs from different namespaces with the minimum required permissions.
- port-forward: Uses
kubectl port-forward(default, works everywhere) - nodeport: Creates a NodePort service (requires node access)
- multus: Uses Multus bridge networking (requires Multus CNI)
When using kubevirt_network_mode: multus, specify one or more Multus attachments via an unprefixed networks: array. Each item requires a unique name and the Multus networkName provided as multus_network_name.
HOSTS:
multus-vm:
platform: el-8-x86_64
hypervisor: kubevirt
kubevirt_vm_image: docker://quay.io/kubevirt/fedora-cloud-container-disk-demo
kubevirt_network_mode: multus
kubevirt_ssh_key: ~/.ssh/id_rsa.pub
networks:
- name: ext0
multus_network_name: my-bridge-network
- name: ext1
multus_network_name: another-network# beaker-hosts.yaml
HOSTS:
puppet-agent:
platform: el-8-x86_64
hypervisor: kubevirt
kubevirt_vm_image: docker://quay.io/kubevirt/centos-stream8-container-disk-demo
kubevirt_network_mode: port-forward
kubevirt_ssh_key: ~/.ssh/id_rsa.pub
kubevirt_cpus: 2
kubevirt_memory: 4Gi
CONFIG:
# Global KubeVirt configuration
kubeconfig: ~/.kube/config
namespace: beaker-tests
ssh:
auth_methods: ['publickey']# spec/acceptance/basic_spec.rb
require 'spec_helper_acceptance'
describe 'basic functionality' do
context 'on KubeVirt VM' do
it 'should provision successfully' do
expect(fact_on(default, 'kernel')).to eq('Linux')
end
it 'should have SSH access' do
result = on(default, 'echo "Hello from KubeVirt VM"')
expect(result.stdout.strip).to eq('Hello from KubeVirt VM')
end
end
endAll resources created are labeled for traceability and cleanup:
beaker/test-group: Identifies the run (e.g.,beaker-<hex>)beaker/host: Host name from your Beaker inventory
These labels are used during cleanup to remove VMs, secrets, and services associated with the test group.
- KubeVirt and Kubernetes cluster access via
kubeconfig - For
port-forwardnetworking mode:kubectlaccess to the cluster nodes and permission to port-forward
After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and the created tag, and push the .gem file to rubygems.org.
Bug reports and pull requests are welcome on GitHub at https://github.com/voxpupuli/beaker-kubevirt.
The gem is available as open source under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.