Skip to content

Commit f4b4437

Browse files
authored
Validate installation of vagrant-libvirt on multiple distros (#5)
Add the basic structure required to trigger testing all distributions currently supported when an update is proposed to the .gitmodules file. Use docker containers for the distros to validate linking of libraries allow the vagrant bindings to work as expected to use libvirt from the distro to launch the VM with the necessary limitation that it will not be a perfect check. Using qemu to spin up the distros for a more accurate check is not possible due to the performance overhead as github actions do not allow for nested virtualization. This can be used as a proxy to pick up latest updates from vagrant-libvirt on a daily basis via dependabot in the hope of maintaining a set of working instructions for each distribution.
1 parent c541419 commit f4b4437

File tree

15 files changed

+743
-147
lines changed

15 files changed

+743
-147
lines changed

.github/workflows/distro-install.yml

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
name: Distribution Install
2+
3+
on:
4+
pull_request:
5+
6+
jobs:
7+
generate-matrix:
8+
runs-on: ubuntu-20.04
9+
outputs:
10+
matrix: ${{ steps.generate-matrix.outputs.matrix }}
11+
steps:
12+
- uses: actions/checkout@v2
13+
- name: Generate matrix
14+
id: generate-matrix
15+
run: |
16+
tests="$(ruby boxes.rb | jq -c -r '. | keys')"
17+
echo "::set-output name=matrix::${tests}"
18+
19+
verify-install:
20+
needs: generate-matrix
21+
runs-on: ubuntu-20.04
22+
env:
23+
VAGRANT_DEFAULT_PROVIDER: docker
24+
VAGRANT_LIBVIRT_DRIVER: qemu
25+
strategy:
26+
fail-fast: false
27+
matrix:
28+
test_name: ${{ fromJSON(needs.generate-matrix.outputs.matrix) }}
29+
30+
steps:
31+
- uses: actions/checkout@v2
32+
with:
33+
fetch-depth: 0
34+
submodules: recursive
35+
- name: Disable apparmor to allow containers use alternative paths
36+
run: |
37+
sudo systemctl stop apparmor
38+
- name: Set up version to test
39+
run: |
40+
echo "QA_VAGRANT_LIBVIRT_VERSION=git-$(git submodule status -- vagrant-libvirt | cut -d' ' -f2)" >> ${GITHUB_ENV}
41+
- name: Set up libvirt
42+
run: |
43+
./scripts/install.bash --vagrant-only -- 2.2.19
44+
- uses: actions/cache@v2
45+
with:
46+
path: ~/.vagrant.d/boxes
47+
key: ${{ runner.os }}-${{ matrix.test_name }}
48+
restore-keys: |
49+
${{ runner.os }}-
50+
- name: launch target distro
51+
run: |
52+
vagrant up --no-provision ${{ matrix.test_name }}
53+
54+
- name: test vagrant-libvirt in target distro
55+
run: |
56+
vagrant provision ${{ matrix.test_name }}
57+
58+
finish:
59+
needs: verify-install
60+
runs-on: ubuntu-latest
61+
steps:
62+
- name: Matrix finished
63+
run: |
64+
echo "success"

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "vagrant-libvirt"]
2+
path = vagrant-libvirt
3+
url = ../vagrant-libvirt.git

Vagrantfile

Lines changed: 58 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,9 @@
11
# -*- mode: ruby -*-
22
# vi: set ft=ruby :
33

4-
ENV['VAGRANT_DEFAULT_PROVIDER'] = 'libvirt'
4+
ENV['VAGRANT_DEFAULT_PROVIDER'] ||= 'libvirt'
55

6-
# Allow for passing test versions with env vars
7-
if ENV['QA_VAGRANT_VERSION'].nil? || ENV['QA_VAGRANT_VERSION'] == "latest"
8-
# If not specified, fetch the latest version using built-in 'version' plugin
9-
#
10-
# NOTE: we 'cd /tmp' to avoid invoking Vagrant against this very Vagrantfile but
11-
# that may not always work. There is probably a better way by leveraging
12-
# VagrantPlugins::CommandVersion::Command and using 'version-latest'
13-
#
14-
latest = `cd /tmp; vagrant version | grep Latest | awk '{ print $3 }'`
15-
QA_VAGRANT_VERSION = latest.strip
16-
else
17-
QA_VAGRANT_VERSION = ENV['QA_VAGRANT_VERSION']
18-
end
19-
20-
if ENV['QA_VAGRANT_LIBVIRT_VERSION'].nil?
21-
# If not specified, we just install latest published version
22-
QA_VAGRANT_LIBVIRT_INSTALL_OPTS = "vagrant-libvirt"
23-
QA_VAGRANT_LIBVIRT_VERSION = "latest"
24-
elsif ENV['QA_VAGRANT_LIBVIRT_VERSION'] == "master"
25-
QA_VAGRANT_LIBVIRT_INSTALL_OPTS = "../vagrant-libvirt/vagrant-libvirt-*.gem"
26-
QA_VAGRANT_LIBVIRT_VERSION = "master"
27-
else
28-
QA_VAGRANT_LIBVIRT_VERSION = ENV['QA_VAGRANT_LIBVIRT_VERSION']
29-
QA_VAGRANT_LIBVIRT_INSTALL_OPTS = "vagrant-libvirt --plugin-version #{QA_VAGRANT_LIBVIRT_VERSION}"
30-
end
31-
32-
APT_ENV_VARS = {
33-
'DEBIAN_FRONTEND': 'noninteractive',
34-
'DEBCONF_NONINTERACTIVE_SEEN': true,
35-
}
36-
37-
def setup_vm_provider(vm)
38-
vm.provider :libvirt do |domain|
39-
domain.driver = 'kvm'
40-
domain.memory = 2048
41-
domain.cpus = 2
42-
domain.nested = true
43-
domain.cpu_mode = 'host-passthrough'
44-
end
45-
end
6+
require_relative './boxes.rb'
467

478
def add_test_provisions(vm)
489
# Workarond for Vagrant bug
@@ -56,9 +17,9 @@ def add_test_provisions(vm)
5617
end
5718
# Testing nested VM provisioning via nested kvm
5819
vm.provision :file, :source => './Vagrantfile.test', :destination => '~/Vagrantfile'
59-
vm.provision :shell, :privileged => false, :inline => <<-EOC
20+
vm.provision :shell, :privileged => false, :env => {'VAGRANT_LOG': 'debug'} ,:inline => <<-EOC
6021
set -e
61-
vagrant destroy -f 2>/dev/null 1>/dev/null
22+
vagrant destroy -f
6223
vagrant up --provider=libvirt
6324
vagrant halt
6425
vagrant destroy -f
@@ -67,88 +28,65 @@ end
6728

6829
Vagrant.configure(2) do |config|
6930

70-
config.vm.define "ubuntu-18.04" do |v|
71-
v.vm.hostname = "ubuntu-18.04"
72-
v.vm.box = "generic/ubuntu1804"
73-
v.vm.synced_folder ".", "/vagrant", disabled: true
74-
setup_vm_provider(v.vm)
75-
v.vm.provision :shell, :inline => 'ln -sf ../run/systemd/resolve/resolv.conf /etc/resolv.conf'
76-
v.vm.provision :shell, :privileged => false, :path => './scripts/install.bash', :args => QA_VAGRANT_VERSION
77-
v.vm.provision :shell, :reset => true, :inline => 'usermod -a -G libvirt vagrant'
78-
add_test_provisions(v.vm)
79-
end
80-
81-
config.vm.define "ubuntu-20.04" do |v|
82-
v.vm.hostname = "ubuntu-20.04"
83-
v.vm.box = "generic/ubuntu2004"
84-
v.vm.synced_folder ".", "/vagrant", disabled: true
85-
setup_vm_provider(v.vm)
86-
v.vm.provision :shell, :inline => 'ln -sf ../run/systemd/resolve/resolv.conf /etc/resolv.conf'
87-
v.vm.provision :shell, :privileged => false, :path => './scripts/install.bash', :args => QA_VAGRANT_VERSION
88-
v.vm.provision :shell, :reset => true, :inline => 'usermod -a -G libvirt vagrant'
89-
add_test_provisions(v.vm)
90-
end
31+
BOXES.each_pair do |name, settings|
32+
config.vm.define name do |machine|
33+
machine.vm.hostname = name
9134

92-
config.vm.define "debian-10" do |v|
93-
v.vm.hostname = "debian-10"
94-
v.vm.box = "generic/debian10"
95-
v.vm.synced_folder ".", "/vagrant", disabled: true
96-
setup_vm_provider(v.vm)
97-
v.vm.provision :shell, :inline => 'sed -i -e "/^dns-nameserver/g" /etc/network/interfaces', :reboot => true
98-
# restarting dnsmasq can require a retry after everything else to come up correctly.
99-
v.vm.provision :shell, :inline => 'apt update && apt install -y dnsmasq && systemctl restart dnsmasq', :env => APT_ENV_VARS
100-
v.vm.provision :shell, :privileged => false, :path => './scripts/install.bash', :args => QA_VAGRANT_VERSION
101-
v.vm.provision :shell, :reset => true, :inline => 'usermod -a -G libvirt vagrant'
102-
add_test_provisions(v.vm)
103-
end
35+
machine.vm.provider :docker do |docker, override|
36+
docker.build_dir = "docker/#{name}"
37+
docker.build_args = "--pull"
38+
docker.has_ssh = true
39+
docker.volumes = [
40+
# allow libvirt in the container to trigger loading modules such as ip6tables
41+
"/lib/modules:/lib/modules",
42+
# next two needed for systemd in container
43+
"/sys/fs/cgroup:/sys/fs/cgroup:ro",
44+
"/sys/fs/cgroup/systemd:/sys/fs/cgroup/systemd:rw",
45+
]
46+
docker.create_args = [
47+
"--privileged",
48+
"--security-opt", "apparmor=unconfined",
49+
"--tmpfs=/run",
50+
"--tmpfs=/tmp:exec",
51+
]
10452

105-
config.vm.define "centos-7" do |v|
106-
v.vm.hostname = "centos-7"
107-
v.vm.box = "centos/7"
108-
v.vm.synced_folder ".", "/vagrant", disabled: true
109-
setup_vm_provider(v.vm)
110-
v.vm.provision :shell, :privileged => false, :path => './scripts/install.bash', :args => QA_VAGRANT_VERSION
111-
v.vm.provision :shell, :reset => true, :inline => 'usermod -a -G libvirt vagrant'
112-
add_test_provisions(v.vm)
113-
end
53+
# Note that must add all provisioners using the same logic as vagrant does
54+
# not order machine.vm.provision and override.vm.provision according to
55+
# order in the Vagrantfile and instead override will always is appended last.
56+
[].concat(
57+
settings.fetch(:docker, {}).fetch(:provision, [])
58+
).concat(
59+
settings.fetch(:provision, DEFAULT_PROVISION)
60+
).concat(
61+
settings.fetch(:docker, {}).fetch(:post_install, [])
62+
).each do |p|
63+
override.vm.provision :shell, **p
64+
end
11465

115-
config.vm.define "centos-8" do |v|
116-
v.vm.hostname = "centos-8"
117-
v.vm.box = "centos/8"
118-
v.vm.synced_folder ".", "/vagrant", disabled: true
119-
setup_vm_provider(v.vm)
120-
v.vm.provision :shell, :privileged => false, :path => './scripts/install.bash', :args => QA_VAGRANT_VERSION
121-
v.vm.provision :shell, :reset => true, :inline => 'usermod -a -G libvirt vagrant'
122-
add_test_provisions(v.vm)
123-
end
66+
add_test_provisions(override.vm)
67+
end
12468

125-
config.vm.define "fedora-33" do |v|
126-
v.vm.hostname = "fedora-33"
127-
v.vm.box = "generic/fedora33"
128-
v.vm.synced_folder ".", "/vagrant", disabled: true
129-
setup_vm_provider(v.vm)
130-
v.vm.provision :shell, :privileged => false, :path => './scripts/install.bash', :args => QA_VAGRANT_VERSION
131-
v.vm.provision :shell, :reset => true, :inline => 'usermod -a -G libvirt vagrant'
132-
add_test_provisions(v.vm)
133-
end
69+
machine.vm.provider :libvirt do |domain, override|
70+
override.vm.box = settings[:libvirt][:box]
71+
domain.driver = ENV.fetch('VAGRANT_LIBVIRT_DRIVER', 'kvm')
72+
domain.memory = 4096
73+
domain.cpus = 2
74+
domain.nested = true
75+
domain.disk_driver :io => 'threads', :cache => 'unsafe'
13476

135-
config.vm.define "fedora-34" do |v|
136-
v.vm.hostname = "fedora-34"
137-
v.vm.box = "generic/fedora34"
138-
v.vm.synced_folder ".", "/vagrant", disabled: true
139-
setup_vm_provider(v.vm)
140-
v.vm.provision :shell, :privileged => false, :path => './scripts/install.bash', :args => QA_VAGRANT_VERSION
141-
v.vm.provision :shell, :reset => true, :inline => 'usermod -a -G libvirt vagrant'
142-
add_test_provisions(v.vm)
143-
end
77+
# Note that must add all provisioners using the same logic as vagrant does
78+
# not order machine.vm.provision and override.vm.provision according to
79+
# order in the Vagrantfile and instead override will always is appended last.
80+
[].concat(
81+
settings.fetch(:libvirt, {}).fetch(:provision, [])
82+
).concat(
83+
settings.fetch(:provision, DEFAULT_PROVISION)
84+
).each do |p|
85+
override.vm.provision :shell, **p
86+
end
14487

145-
config.vm.define "arch" do |v|
146-
v.vm.hostname = "arch"
147-
v.vm.box = "archlinux/archlinux"
148-
v.vm.synced_folder ".", "/vagrant", disabled: true
149-
setup_vm_provider(v.vm)
150-
v.vm.provision :shell, :privileged => false, :path => './scripts/install.bash', :args => QA_VAGRANT_VERSION
151-
v.vm.provision :shell, :privileged => false, :reset => true, :inline => 'sudo usermod -G kvm $(whoami)'
152-
add_test_provisions(v.vm)
88+
add_test_provisions(override.vm)
89+
end
90+
end
15391
end
15492
end

Vagrantfile.test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
ENV['VAGRANT_DEFAULT_PROVIDER'] = 'libvirt'
55

66
Vagrant.configure(2) do |config|
7+
config.vm.boot_timeout = 1200
78
config.vm.define "tiny" do |v|
89
v.vm.box = "infernix/tinycore"
910
v.vm.synced_folder ".", "/vagrant", disabled: true

boxes.rb

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#!/usr/bin/ruby
2+
#
3+
# Allow for passing test versions with env vars
4+
if ENV['QA_VAGRANT_VERSION'].nil? || ENV['QA_VAGRANT_VERSION'] == "latest"
5+
# If not specified, fetch the latest version using built-in 'version' plugin
6+
#
7+
# NOTE: we 'cd /tmp' to avoid invoking Vagrant against this very Vagrantfile but
8+
# that may not always work. There is probably a better way by leveraging
9+
# VagrantPlugins::CommandVersion::Command and using 'version-latest'
10+
#
11+
latest = `cd /tmp; vagrant version | grep Latest | awk '{ print $3 }'`
12+
QA_VAGRANT_VERSION = latest.strip
13+
else
14+
QA_VAGRANT_VERSION = ENV['QA_VAGRANT_VERSION']
15+
end
16+
17+
APT_ENV_VARS = {
18+
'DEBIAN_FRONTEND': 'noninteractive',
19+
'DEBCONF_NONINTERACTIVE_SEEN': true,
20+
}
21+
22+
INSTALL_ENV_VARS = {
23+
'VAGRANT_LIBVIRT_VERSION': ENV.fetch('QA_VAGRANT_LIBVIRT_VERSION', 'latest'),
24+
}
25+
26+
BOXES = {
27+
'ubuntu-18.04' => {
28+
:libvirt => {
29+
:box => "generic/ubuntu1804",
30+
:provision => [
31+
{:inline => 'ln -sf ../run/systemd/resolve/resolv.conf /etc/resolv.conf'},
32+
],
33+
},
34+
},
35+
'ubuntu-20.04' => {
36+
:libvirt => {
37+
:box => "generic/ubuntu2004",
38+
},
39+
},
40+
'debian-10' => {
41+
:libvirt => {
42+
:box => "generic/debian10",
43+
:provision => [
44+
{:name => 'disable dns-nameservers', :inline => 'sed -i -e "/^dns-nameserver/g" /etc/network/interfaces', :reboot => true},
45+
# restarting dnsmasq can require a retry after everything else to come up correctly.
46+
{:name => 'install dnsmasq', :inline => 'apt update && apt install -y dnsmasq && systemctl restart dnsmasq', :env => APT_ENV_VARS},
47+
],
48+
},
49+
},
50+
'centos-7' => {
51+
:libvirt => {
52+
:box => "generic/centos7",
53+
},
54+
},
55+
'centos-8' => {
56+
:libvirt => {
57+
:box => "generic/centos8",
58+
},
59+
},
60+
'fedora-33' => {
61+
:libvirt => {
62+
:box => "generic/fedora33",
63+
},
64+
},
65+
'fedora-34' => {
66+
:libvirt => {
67+
:box => "generic/fedora34",
68+
},
69+
},
70+
'archlinux' => {
71+
:libvirt => {
72+
:box => "archlinux/archlinux",
73+
},
74+
},
75+
}
76+
77+
DEFAULT_PROVISION = [
78+
{:name => 'install script', :privileged => false, :path => './scripts/install.bash', :args => "--vagrant-version #{QA_VAGRANT_VERSION}", :env => INSTALL_ENV_VARS},
79+
{:name => 'setup group', :reset => true, :inline => 'usermod -a -G libvirt vagrant'},
80+
{:name => 'debug system capabilities', :privileged => false, :inline => 'virsh --connect qemu:///system capabilities'},
81+
{:name => 'debug uri', :privileged => false, :inline => 'virsh uri'},
82+
]
83+
84+
if __FILE__ == $0
85+
require 'json'
86+
puts JSON.pretty_generate(BOXES)
87+
end

0 commit comments

Comments
 (0)