vagrant-libvirt 0.1.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +321 -76
- data/lib/vagrant-libvirt/action.rb +1 -1
- data/lib/vagrant-libvirt/action/create_domain.rb +54 -14
- data/lib/vagrant-libvirt/action/create_domain_volume.rb +0 -2
- data/lib/vagrant-libvirt/action/create_network_interfaces.rb +1 -0
- data/lib/vagrant-libvirt/action/forward_ports.rb +4 -3
- data/lib/vagrant-libvirt/action/handle_box_image.rb +6 -3
- data/lib/vagrant-libvirt/action/package_domain.rb +10 -4
- data/lib/vagrant-libvirt/action/prune_nfs_exports.rb +4 -3
- data/lib/vagrant-libvirt/action/start_domain.rb +86 -29
- data/lib/vagrant-libvirt/action/wait_till_up.rb +7 -27
- data/lib/vagrant-libvirt/cap/public_address.rb +16 -0
- data/lib/vagrant-libvirt/config.rb +233 -32
- data/lib/vagrant-libvirt/driver.rb +49 -32
- data/lib/vagrant-libvirt/plugin.rb +6 -0
- data/lib/vagrant-libvirt/provider.rb +2 -9
- data/lib/vagrant-libvirt/templates/domain.xml.erb +34 -5
- data/lib/vagrant-libvirt/templates/public_interface.xml.erb +5 -1
- data/lib/vagrant-libvirt/util.rb +1 -0
- data/lib/vagrant-libvirt/util/erb_template.rb +6 -7
- data/lib/vagrant-libvirt/util/ui.rb +23 -0
- data/lib/vagrant-libvirt/version +1 -0
- data/lib/vagrant-libvirt/version.rb +72 -1
- data/spec/spec_helper.rb +28 -2
- data/spec/support/binding_proc.rb +24 -0
- data/spec/support/libvirt_context.rb +3 -1
- data/spec/support/sharedcontext.rb +7 -3
- data/spec/unit/action/create_domain_spec.rb +160 -0
- data/spec/unit/action/create_domain_spec/default_system_storage_pool.xml +17 -0
- data/spec/unit/action/create_domain_spec/default_user_storage_pool.xml +17 -0
- data/spec/unit/action/destroy_domain_spec.rb +2 -2
- data/spec/unit/action/set_name_of_domain_spec.rb +2 -2
- data/spec/unit/action/start_domain_spec.rb +231 -0
- data/spec/unit/action/start_domain_spec/clock_timer_rtc.xml +50 -0
- data/spec/unit/action/start_domain_spec/default.xml +48 -0
- data/spec/unit/action/start_domain_spec/default_added_tpm_path.xml +48 -0
- data/spec/unit/action/start_domain_spec/default_added_tpm_version.xml +48 -0
- data/spec/unit/action/wait_till_up_spec.rb +32 -9
- data/spec/unit/config_spec.rb +438 -0
- data/spec/unit/provider_spec.rb +11 -0
- data/spec/unit/templates/domain_all_settings.xml +8 -3
- data/spec/unit/templates/domain_custom_cpu_model.xml +4 -1
- data/spec/unit/templates/domain_defaults.xml +4 -1
- data/spec/unit/templates/domain_spec.rb +82 -2
- data/spec/unit/templates/tpm/version_1.2.xml +54 -0
- data/spec/unit/templates/tpm/version_2.0.xml +53 -0
- metadata +62 -6
@@ -60,12 +60,12 @@ module VagrantPlugins
|
|
60
60
|
@@system_connection
|
61
61
|
end
|
62
62
|
|
63
|
-
def get_domain(
|
63
|
+
def get_domain(machine)
|
64
64
|
begin
|
65
|
-
domain = connection.servers.get(
|
65
|
+
domain = connection.servers.get(machine.id)
|
66
66
|
rescue Libvirt::RetrieveError => e
|
67
67
|
if e.libvirt_code == ProviderLibvirt::Util::ErrorCodes::VIR_ERR_NO_DOMAIN
|
68
|
-
@logger.debug("machine #{
|
68
|
+
@logger.debug("machine #{machine.name} domain not found #{e}.")
|
69
69
|
return nil
|
70
70
|
else
|
71
71
|
raise e
|
@@ -75,36 +75,35 @@ module VagrantPlugins
|
|
75
75
|
domain
|
76
76
|
end
|
77
77
|
|
78
|
-
def created?(
|
79
|
-
domain = get_domain(
|
78
|
+
def created?(machine)
|
79
|
+
domain = get_domain(machine)
|
80
80
|
!domain.nil?
|
81
81
|
end
|
82
82
|
|
83
83
|
def get_ipaddress(machine)
|
84
84
|
# Find the machine
|
85
|
-
domain = get_domain(machine
|
86
|
-
if @machine.provider_config.qemu_use_session
|
87
|
-
return get_ipaddress_system domain.mac
|
88
|
-
end
|
85
|
+
domain = get_domain(machine)
|
89
86
|
|
90
87
|
if domain.nil?
|
91
88
|
# The machine can't be found
|
92
89
|
return nil
|
93
90
|
end
|
94
91
|
|
95
|
-
|
96
|
-
|
92
|
+
get_domain_ipaddress(machine, domain)
|
93
|
+
end
|
94
|
+
|
95
|
+
def get_domain_ipaddress(machine, domain)
|
96
|
+
if @machine.provider_config.qemu_use_session
|
97
|
+
return get_ipaddress_from_system domain.mac
|
98
|
+
end
|
99
|
+
|
100
|
+
# Get IP address from dhcp leases table
|
97
101
|
begin
|
98
|
-
domain
|
99
|
-
addresses.each_pair do |_type, ip|
|
100
|
-
# Multiple leases are separated with a newline, return only
|
101
|
-
# the most recent address
|
102
|
-
ip_address = ip[0].split("\n").first unless ip[0].nil?
|
103
|
-
end
|
104
|
-
!ip_address.nil?
|
105
|
-
end
|
102
|
+
ip_address = get_ipaddress_from_domain(domain)
|
106
103
|
rescue Fog::Errors::TimeoutError
|
107
104
|
@logger.info('Timeout at waiting for an ip address for machine %s' % machine.name)
|
105
|
+
|
106
|
+
raise
|
108
107
|
end
|
109
108
|
|
110
109
|
unless ip_address
|
@@ -115,7 +114,24 @@ module VagrantPlugins
|
|
115
114
|
ip_address
|
116
115
|
end
|
117
116
|
|
118
|
-
def
|
117
|
+
def state(machine)
|
118
|
+
# may be other error states with initial retreival we can't handle
|
119
|
+
begin
|
120
|
+
domain = get_domain(machine)
|
121
|
+
rescue Libvirt::RetrieveError => e
|
122
|
+
@logger.debug("Machine #{machine.id} not found #{e}.")
|
123
|
+
return :not_created
|
124
|
+
end
|
125
|
+
|
126
|
+
# TODO: terminated no longer appears to be a valid fog state, remove?
|
127
|
+
return :not_created if domain.nil? || domain.state.to_sym == :terminated
|
128
|
+
|
129
|
+
domain.state.tr('-', '_').to_sym
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
def get_ipaddress_from_system(mac)
|
119
135
|
ip_address = nil
|
120
136
|
|
121
137
|
system_connection.list_all_networks.each do |net|
|
@@ -125,23 +141,24 @@ module VagrantPlugins
|
|
125
141
|
break if ip_address
|
126
142
|
end
|
127
143
|
|
128
|
-
|
144
|
+
ip_address
|
129
145
|
end
|
130
146
|
|
131
|
-
def
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
147
|
+
def get_ipaddress_from_domain(domain)
|
148
|
+
ip_address = nil
|
149
|
+
domain.wait_for(2) do
|
150
|
+
addresses.each_pair do |type, ip|
|
151
|
+
# Multiple leases are separated with a newline, return only
|
152
|
+
# the most recent address
|
153
|
+
ip_address = ip[0].split("\n").first if ip[0] != nil
|
154
|
+
end
|
139
155
|
|
140
|
-
|
141
|
-
|
156
|
+
ip_address != nil
|
157
|
+
end
|
142
158
|
|
143
|
-
|
159
|
+
ip_address
|
144
160
|
end
|
161
|
+
|
145
162
|
end
|
146
163
|
end
|
147
164
|
end
|
@@ -26,6 +26,7 @@ module VagrantPlugins
|
|
26
26
|
end
|
27
27
|
|
28
28
|
action_hook(:remove_libvirt_image) do |hook|
|
29
|
+
require_relative 'action'
|
29
30
|
hook.after Vagrant::Action::Builtin::BoxRemove, Action.remove_libvirt_image
|
30
31
|
end
|
31
32
|
|
@@ -39,6 +40,11 @@ module VagrantPlugins
|
|
39
40
|
Cap::NicMacAddresses
|
40
41
|
end
|
41
42
|
|
43
|
+
provider_capability(:libvirt, :public_address) do
|
44
|
+
require_relative 'cap/public_address'
|
45
|
+
Cap::PublicAddress
|
46
|
+
end
|
47
|
+
|
42
48
|
# lower priority than nfs or rsync
|
43
49
|
# https://github.com/vagrant-libvirt/vagrant-libvirt/pull/170
|
44
50
|
synced_folder('9p', 4) do
|
@@ -68,14 +68,7 @@ module VagrantPlugins
|
|
68
68
|
forward_x11: @machine.config.ssh.forward_x11
|
69
69
|
}
|
70
70
|
|
71
|
-
if @machine.provider_config.
|
72
|
-
ssh_info[:proxy_command] =
|
73
|
-
"ssh '#{@machine.provider_config.host}' " \
|
74
|
-
"-l '#{@machine.provider_config.username}' " \
|
75
|
-
"-i '#{@machine.provider_config.id_ssh_key_file}' " \
|
76
|
-
'nc %h %p'
|
77
|
-
|
78
|
-
end
|
71
|
+
ssh_info[:proxy_command] = @machine.provider_config.proxy_command if @machine.provider_config.proxy_command
|
79
72
|
|
80
73
|
ssh_info
|
81
74
|
end
|
@@ -98,7 +91,7 @@ module VagrantPlugins
|
|
98
91
|
state_id = nil
|
99
92
|
state_id = :not_created unless @machine.id
|
100
93
|
state_id = :not_created if
|
101
|
-
!state_id && (!@machine.id || !driver.created?(@machine
|
94
|
+
!state_id && (!@machine.id || !driver.created?(@machine))
|
102
95
|
# Query the driver for the current state of the machine
|
103
96
|
state_id = driver.state(@machine) if @machine.id && !state_id
|
104
97
|
state_id = :unknown unless state_id
|
@@ -1,5 +1,7 @@
|
|
1
1
|
<domain type='<%= @domain_type %>' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
|
2
2
|
<name><%= @name %></name>
|
3
|
+
<title><%= @title %></title>
|
4
|
+
<description><%= @description %></description>
|
3
5
|
<uuid><%= @uuid %></uuid>
|
4
6
|
<memory><%= @memory_size %></memory>
|
5
7
|
<vcpu<% if @cpuset %> cpuset='<%= @cpuset %>'<% end %>><%= @cpus %></vcpu>
|
@@ -102,14 +104,22 @@
|
|
102
104
|
</hyperv>
|
103
105
|
<% end %>
|
104
106
|
</features>
|
105
|
-
<clock offset='
|
107
|
+
<clock offset='<%= @clock_offset %>'>
|
108
|
+
<% @clock_timers.each do |clock_timer| %>
|
109
|
+
<timer<% clock_timer.each do |attr, value| %> <%= attr %>='<%= value %>'<% end %>/>
|
110
|
+
<% end %>
|
111
|
+
</clock>
|
106
112
|
<devices>
|
107
113
|
<% if @emulator_path %>
|
108
114
|
<emulator><%= @emulator_path %></emulator>
|
109
115
|
<% end %>
|
110
116
|
<% if @domain_volume_path %>
|
111
117
|
<disk type='file' device='disk'>
|
112
|
-
<driver name='qemu' type='qcow2'
|
118
|
+
<driver name='qemu' type='qcow2' <%=
|
119
|
+
@disk_driver_opts.empty? ? "cache='#{@domain_volume_cache}'" :
|
120
|
+
@disk_driver_opts.reject { |k,v| v.nil? }
|
121
|
+
.map { |k,v| "#{k}='#{v}'"}
|
122
|
+
.join(' ') -%>/>
|
113
123
|
<source file='<%= @domain_volume_path %>'/>
|
114
124
|
<%# we need to ensure a unique target dev -%>
|
115
125
|
<target dev='<%= @disk_device %>' bus='<%= @disk_bus %>'/>
|
@@ -118,7 +128,12 @@
|
|
118
128
|
<%# additional disks -%>
|
119
129
|
<% @disks.each do |d| -%>
|
120
130
|
<disk type='file' device='disk'>
|
121
|
-
<driver name='qemu' type='<%= d[:type] %>'
|
131
|
+
<driver name='qemu' type='<%= d[:type] %>' <%=
|
132
|
+
d.select { |k,_| [:cache, :io, :copy_on_read, :discard, :detect_zeroes].include? k }
|
133
|
+
.reject { |k,v| v.nil? }
|
134
|
+
.map { |k,v| "#{k}='#{v}'"}
|
135
|
+
.join(' ')
|
136
|
+
-%>/>
|
122
137
|
<source file='<%= d[:absolute_path] %>'/>
|
123
138
|
<target dev='<%= d[:device] %>' bus='<%= d[:bus] %>'/>
|
124
139
|
<% if d[:shareable] %>
|
@@ -127,6 +142,9 @@
|
|
127
142
|
<% if d[:serial] %>
|
128
143
|
<serial><%= d[:serial] %></serial>
|
129
144
|
<% end %>
|
145
|
+
<% if d[:wwn] %>
|
146
|
+
<wwn><%= d[:wwn] %></wwn>
|
147
|
+
<% end %>
|
130
148
|
<%# this will get auto generated by Libvirt
|
131
149
|
<address type='pci' domain='0x0000' bus='0x00' slot='???' function='0x0'/>
|
132
150
|
-%>
|
@@ -252,11 +270,13 @@
|
|
252
270
|
<% end %>
|
253
271
|
<% end -%>
|
254
272
|
|
255
|
-
<% if @tpm_path -%>
|
273
|
+
<% if @tpm_path || @tpm_version -%>
|
256
274
|
<%# TPM Device -%>
|
257
275
|
<tpm model='<%= @tpm_model %>'>
|
258
|
-
<backend type='<%= @tpm_type %>'
|
276
|
+
<backend type='<%= @tpm_type %>'<% if @tpm_version %> version='<%= @tpm_version %>'<% end %>>
|
277
|
+
<% if @tpm_path -%>
|
259
278
|
<device path='<%= @tpm_path %>'/>
|
279
|
+
<% end -%>
|
260
280
|
</backend>
|
261
281
|
</tpm>
|
262
282
|
<% end -%>
|
@@ -264,6 +284,15 @@
|
|
264
284
|
<%# USB Controller -%>
|
265
285
|
<controller type='usb' model='<%= @usbctl_dev[:model] %>' <%= "ports=\"#{@usbctl_dev[:ports]}\" " if @usbctl_dev[:ports] %>/>
|
266
286
|
<% end %>
|
287
|
+
<% unless @memballoon_enabled.nil? %>
|
288
|
+
<% if @memballoon_enabled %>
|
289
|
+
<memballoon model='<%= @memballoon_model %>'>
|
290
|
+
<address type='pci' domain='0x0000' bus='<%= @memballoon_pci_bus %>' slot='<%= @memballoon_pci_slot %>' function='0x0'/>
|
291
|
+
</memballoon>
|
292
|
+
<% else %>
|
293
|
+
<memballoon model='none'/>
|
294
|
+
<% end %>
|
295
|
+
<% end %>
|
267
296
|
</devices>
|
268
297
|
|
269
298
|
<% if not @qemu_args.empty? or not @qemu_env.empty? %>
|
@@ -18,7 +18,11 @@
|
|
18
18
|
<driver name='<%=@driver_name%>'/>
|
19
19
|
<% end %>
|
20
20
|
<% if @ovs %>
|
21
|
-
<virtualport type='openvswitch'
|
21
|
+
<virtualport type='openvswitch'>
|
22
|
+
<% if @ovs_interfaceid %>
|
23
|
+
<parameters interfaceid='<%=@ovs_interfaceid%>'/>
|
24
|
+
<% end %>
|
25
|
+
</virtualport>
|
22
26
|
<% end %>
|
23
27
|
<% if @pci_bus and @pci_slot %>
|
24
28
|
<address type='pci' bus='<%=@pci_bus%>' slot='<%=@pci_slot%>' />
|
data/lib/vagrant-libvirt/util.rb
CHANGED
@@ -1,20 +1,19 @@
|
|
1
|
-
require 'erubis'
|
2
|
-
|
3
1
|
module VagrantPlugins
|
4
2
|
module ProviderLibvirt
|
5
3
|
module Util
|
6
4
|
module ErbTemplate
|
7
5
|
# TODO: remove and use nokogiri builder
|
8
|
-
# TODO: might be a chance to use vagrant template system according to https://github.com/mitchellh/vagrant/issues/3231
|
9
6
|
def to_xml(template_name = nil, data = binding)
|
10
7
|
erb = template_name || self.class.to_s.split('::').last.downcase
|
11
|
-
path = File.join(File.dirname(__FILE__), '..', 'templates'
|
12
|
-
|
13
|
-
template = File.read(path)
|
8
|
+
path = File.join(File.dirname(__FILE__), '..', 'templates')
|
9
|
+
template = "#{erb}.xml"
|
14
10
|
|
15
11
|
# TODO: according to erubis documentation, we should rather use evaluate and forget about
|
16
12
|
# binding since the template may then change variables values
|
17
|
-
|
13
|
+
Vagrant::Util::TemplateRenderer.render_with(:render, template, template_root: path) do |renderer|
|
14
|
+
iv = data.eval ("instance_variables.collect {|i| [i, instance_variable_get(i.to_sym)]}")
|
15
|
+
iv.each {|k, v| renderer.instance_variable_set(k, v)}
|
16
|
+
end
|
18
17
|
end
|
19
18
|
end
|
20
19
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
module VagrantPlugins
|
3
|
+
module ProviderLibvirt
|
4
|
+
module Util
|
5
|
+
module Ui
|
6
|
+
# Since v2.2.8 Vagrant support --no-tty option, which silences
|
7
|
+
# progress bars and other interactive elements for cleaner logs
|
8
|
+
# in scripts, but requires a slight change in UI object handling.
|
9
|
+
# This helper allows the vagrant-libvirt plugin to stay compatible
|
10
|
+
# with the older Vagrant versions.
|
11
|
+
# See: https://github.com/hashicorp/vagrant/pull/11465/
|
12
|
+
def rewriting(ui)
|
13
|
+
if ui.respond_to?(:rewriting)
|
14
|
+
ui.rewriting {|rw| yield rw}
|
15
|
+
else
|
16
|
+
yield ui
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
0.4.1
|
@@ -1,5 +1,76 @@
|
|
1
|
+
require 'open3'
|
2
|
+
require 'tmpdir'
|
3
|
+
|
1
4
|
module VagrantPlugins
|
2
5
|
module ProviderLibvirt
|
3
|
-
|
6
|
+
VERSION_FILE = File.dirname(__FILE__) + "/version"
|
7
|
+
|
8
|
+
GIT_ARCHIVE_VERSION = "$Format:%H %D$"
|
9
|
+
|
10
|
+
HOMEPAGE = 'https://github.com/vagrant-libvirt/vagrant-libvirt'
|
11
|
+
|
12
|
+
def self.get_version
|
13
|
+
if File.exist?(VERSION_FILE)
|
14
|
+
# built gem
|
15
|
+
version = File.read(VERSION_FILE)
|
16
|
+
elsif self.inside_git_repository
|
17
|
+
# local repo
|
18
|
+
git_version = `git describe --tags`
|
19
|
+
version = self.version_from_describe(git_version)
|
20
|
+
elsif !GIT_ARCHIVE_VERSION.start_with?('$Format')
|
21
|
+
# archive - format string replaced during export
|
22
|
+
hash, refs = GIT_ARCHIVE_VERSION.split(' ', 2)
|
23
|
+
|
24
|
+
tag = refs.split(',').select { |ref| ref.strip.start_with?("tag:") }.first
|
25
|
+
if tag != nil
|
26
|
+
# tagged
|
27
|
+
version = tag.strip.split(' ').last
|
28
|
+
else
|
29
|
+
version = ""
|
30
|
+
# arbitrary branch/commit
|
31
|
+
Dir.mktmpdir do |dir|
|
32
|
+
stdout_and_stderr, status = Open3.capture2e("git -C #{dir} clone --bare #{HOMEPAGE}")
|
33
|
+
raise "failed to clone original to resolve version: #{stdout_and_stderr}" unless status.success?
|
34
|
+
|
35
|
+
stdout_and_stderr, status = Open3.capture2e("git --git-dir=#{dir}/vagrant-libvirt.git describe --tags #{hash}")
|
36
|
+
raise "failed to determine version for #{hash}: #{stdout_and_stderr}" unless status.success?
|
37
|
+
|
38
|
+
version = version_from_describe(stdout_and_stderr)
|
39
|
+
end
|
40
|
+
|
41
|
+
# in this case write the version file to avoid cloning a second time
|
42
|
+
File.write(VERSION_FILE, version)
|
43
|
+
end
|
44
|
+
else
|
45
|
+
# no idea
|
46
|
+
version = "9999"
|
47
|
+
end
|
48
|
+
|
49
|
+
return version.freeze
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.write_version
|
53
|
+
File.write(VERSION_FILE, self.get_version)
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def self.inside_git_repository
|
59
|
+
_, status = Open3.capture2e("git rev-parse --git-dir")
|
60
|
+
|
61
|
+
status.success?
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.version_from_describe(describe)
|
65
|
+
version_parts = describe.split('-').first(2) # drop the git sha if it exists
|
66
|
+
if version_parts.length > 1
|
67
|
+
# increment the patch number so that this is marked as a pre-release of the
|
68
|
+
# next possible release
|
69
|
+
main_version_parts = Gem::Version.new(version_parts[0]).segments
|
70
|
+
main_version_parts[-1] = main_version_parts.last + 1
|
71
|
+
version_parts = main_version_parts + ["pre", version_parts[1]]
|
72
|
+
end
|
73
|
+
version = version_parts.join(".")
|
74
|
+
end
|
4
75
|
end
|
5
76
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,5 +1,31 @@
|
|
1
|
-
require '
|
2
|
-
|
1
|
+
require 'simplecov'
|
2
|
+
require 'simplecov-lcov'
|
3
|
+
|
4
|
+
# patch simplecov configuration
|
5
|
+
if ! SimpleCov::Configuration.method_defined? :branch_coverage?
|
6
|
+
module SimpleCov
|
7
|
+
module Configuration
|
8
|
+
def branch_coverage?
|
9
|
+
return false
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
SimpleCov::Formatter::LcovFormatter.config do |config|
|
16
|
+
config.report_with_single_file = true
|
17
|
+
config.single_report_path = 'coverage/lcov.info'
|
18
|
+
end
|
19
|
+
|
20
|
+
SimpleCov.formatters = SimpleCov::Formatter::MultiFormatter.new(
|
21
|
+
[
|
22
|
+
SimpleCov::Formatter::HTMLFormatter,
|
23
|
+
SimpleCov::Formatter::LcovFormatter,
|
24
|
+
]
|
25
|
+
)
|
26
|
+
SimpleCov.start do
|
27
|
+
add_filter 'spec/'
|
28
|
+
end
|
3
29
|
|
4
30
|
require 'vagrant-libvirt'
|
5
31
|
require 'support/environment_helper'
|