vagrant-libvirt 0.4.0 → 0.5.3
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 +251 -33
- data/lib/vagrant-libvirt/action.rb +7 -1
- data/lib/vagrant-libvirt/action/clean_machine_folder.rb +30 -0
- data/lib/vagrant-libvirt/action/create_domain.rb +28 -11
- data/lib/vagrant-libvirt/action/create_domain_volume.rb +57 -55
- data/lib/vagrant-libvirt/action/create_network_interfaces.rb +0 -3
- data/lib/vagrant-libvirt/action/create_networks.rb +11 -4
- data/lib/vagrant-libvirt/action/destroy_domain.rb +1 -1
- data/lib/vagrant-libvirt/action/forward_ports.rb +36 -37
- data/lib/vagrant-libvirt/action/halt_domain.rb +25 -9
- data/lib/vagrant-libvirt/action/handle_box_image.rb +170 -77
- data/lib/vagrant-libvirt/action/is_running.rb +1 -3
- data/lib/vagrant-libvirt/action/is_suspended.rb +4 -4
- data/lib/vagrant-libvirt/action/set_boot_order.rb +6 -2
- data/lib/vagrant-libvirt/action/wait_till_up.rb +1 -25
- data/lib/vagrant-libvirt/cap/{mount_p9.rb → mount_9p.rb} +2 -2
- data/lib/vagrant-libvirt/cap/mount_virtiofs.rb +37 -0
- data/lib/vagrant-libvirt/cap/{synced_folder.rb → synced_folder_9p.rb} +4 -5
- data/lib/vagrant-libvirt/cap/synced_folder_virtiofs.rb +109 -0
- data/lib/vagrant-libvirt/config.rb +34 -2
- data/lib/vagrant-libvirt/driver.rb +3 -1
- data/lib/vagrant-libvirt/errors.rb +24 -1
- data/lib/vagrant-libvirt/plugin.rb +14 -5
- data/lib/vagrant-libvirt/templates/domain.xml.erb +7 -6
- data/lib/vagrant-libvirt/templates/private_network.xml.erb +1 -1
- data/lib/vagrant-libvirt/util/byte_number.rb +71 -0
- data/lib/vagrant-libvirt/util/network_util.rb +21 -3
- data/lib/vagrant-libvirt/version +1 -1
- data/locales/en.yml +12 -0
- data/spec/spec_helper.rb +9 -1
- data/spec/support/binding_proc.rb +24 -0
- data/spec/support/matchers/have_file_content.rb +63 -0
- data/spec/unit/action/clean_machine_folder_spec.rb +58 -0
- data/spec/unit/action/create_domain_spec.rb +15 -5
- data/spec/unit/action/create_domain_spec/additional_disks_domain.xml +54 -0
- data/spec/unit/action/create_domain_spec/default_domain.xml +49 -0
- data/spec/unit/action/create_domain_volume_spec.rb +104 -0
- data/spec/unit/action/create_domain_volume_spec/one_disk_in_storage.xml +21 -0
- data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_0.xml +21 -0
- data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_1.xml +21 -0
- data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_2.xml +21 -0
- data/spec/unit/action/destroy_domain_spec.rb +1 -1
- data/spec/unit/action/forward_ports_spec.rb +202 -0
- data/spec/unit/action/halt_domain_spec.rb +90 -0
- data/spec/unit/action/handle_box_image_spec.rb +441 -0
- data/spec/unit/action/wait_till_up_spec.rb +11 -15
- data/spec/unit/config_spec.rb +12 -9
- data/spec/unit/templates/domain_all_settings.xml +8 -0
- data/spec/unit/templates/domain_spec.rb +20 -1
- data/spec/unit/util/byte_number_spec.rb +26 -0
- metadata +52 -18
@@ -0,0 +1,71 @@
|
|
1
|
+
class ByteNumber < Numeric
|
2
|
+
def initialize(int)
|
3
|
+
@int = int
|
4
|
+
end
|
5
|
+
|
6
|
+
def to_s
|
7
|
+
@int.to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_i
|
11
|
+
@int
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_f
|
15
|
+
@int.to_f
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_B
|
19
|
+
to_i
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_KB
|
23
|
+
_compute_unit_to_n_kilo(1)
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_MB
|
27
|
+
_compute_unit_to_n_kilo(2)
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_GB
|
31
|
+
_compute_unit_to_n_kilo(3)
|
32
|
+
end
|
33
|
+
|
34
|
+
def coerce(other)
|
35
|
+
to_i.coerce(other)
|
36
|
+
end
|
37
|
+
|
38
|
+
def <=>(other)
|
39
|
+
to_i <=> other
|
40
|
+
end
|
41
|
+
|
42
|
+
def +(other)
|
43
|
+
to_i + other
|
44
|
+
end
|
45
|
+
|
46
|
+
def -(other)
|
47
|
+
to_i - other
|
48
|
+
end
|
49
|
+
|
50
|
+
def *(other)
|
51
|
+
to_i * other
|
52
|
+
end
|
53
|
+
|
54
|
+
def /(other)
|
55
|
+
to_i / other
|
56
|
+
end
|
57
|
+
|
58
|
+
def pow(n)
|
59
|
+
self.class.new(to_i ** n)
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.from_GB(value)
|
63
|
+
self.new(value*(1024**3))
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
def _compute_unit_to_n_kilo(n=0)
|
68
|
+
(to_f/(1024 ** n)).ceil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
@@ -1,6 +1,15 @@
|
|
1
|
+
require 'ipaddr'
|
1
2
|
require 'nokogiri'
|
2
3
|
require 'vagrant/util/network_ip'
|
3
4
|
|
5
|
+
class IPAddr
|
6
|
+
def get_mask
|
7
|
+
if @addr
|
8
|
+
_to_string(@mask_addr)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
4
13
|
module VagrantPlugins
|
5
14
|
module ProviderLibvirt
|
6
15
|
module Util
|
@@ -19,6 +28,7 @@ module VagrantPlugins
|
|
19
28
|
management_network_pci_bus = env[:machine].provider_config.management_network_pci_bus
|
20
29
|
management_network_pci_slot = env[:machine].provider_config.management_network_pci_slot
|
21
30
|
management_network_domain = env[:machine].provider_config.management_network_domain
|
31
|
+
management_network_mtu = env[:machine].provider_config.management_network_mtu
|
22
32
|
logger.info "Using #{management_network_name} at #{management_network_address} as the management network #{management_network_mode} is the mode"
|
23
33
|
|
24
34
|
begin
|
@@ -70,6 +80,10 @@ module VagrantPlugins
|
|
70
80
|
management_network_options[:domain_name] = management_network_domain
|
71
81
|
end
|
72
82
|
|
83
|
+
unless management_network_mtu.nil?
|
84
|
+
management_network_options[:mtu] = management_network_mtu
|
85
|
+
end
|
86
|
+
|
73
87
|
unless management_network_pci_bus.nil? and management_network_pci_slot.nil?
|
74
88
|
management_network_options[:bus] = management_network_pci_bus
|
75
89
|
management_network_options[:slot] = management_network_pci_slot
|
@@ -97,14 +111,18 @@ module VagrantPlugins
|
|
97
111
|
# store type in options
|
98
112
|
# use default values if not already set
|
99
113
|
options = {
|
100
|
-
iface_type:
|
101
|
-
netmask:
|
114
|
+
iface_type: type,
|
115
|
+
netmask: options[:network_address] ?
|
116
|
+
IPAddr.new(options[:network_address]).get_mask :
|
117
|
+
'255.255.255.0',
|
102
118
|
dhcp_enabled: true,
|
103
119
|
forward_mode: 'nat'
|
104
120
|
}.merge(options)
|
105
121
|
|
106
122
|
if options[:type].to_s == 'dhcp' && options[:ip].nil?
|
107
|
-
options[:network_name] =
|
123
|
+
options[:network_name] = options[:network_name] ?
|
124
|
+
options[:network_name] :
|
125
|
+
'vagrant-private-dhcp'
|
108
126
|
end
|
109
127
|
|
110
128
|
# add to list of networks to check
|
data/lib/vagrant-libvirt/version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.5.3
|
data/locales/en.yml
CHANGED
@@ -72,6 +72,14 @@ en:
|
|
72
72
|
no_storage_pool: |-
|
73
73
|
No usable storage pool found! Please check if storage pool is
|
74
74
|
created and available.
|
75
|
+
box_format_duplicate_volume: |-
|
76
|
+
Encountered a duplicate volume name '%{volume}' generated for disk '%{new_disk}', due to already allocated for disk '%{orig_disk}'.
|
77
|
+
box_format_missing_attribute: |-
|
78
|
+
Invalid box metadata, missing expected attribute: '%{attribute}'
|
79
|
+
bad_box_image: |-
|
80
|
+
Received error when query the box image details from '%{image}'.
|
81
|
+
Stdout: %{out}
|
82
|
+
Stderr: %{err}
|
75
83
|
no_box_volume: |-
|
76
84
|
Volume for box image is missing in storage pools. Try to run vagrant
|
77
85
|
again, or check if storage volume is accessible.
|
@@ -92,10 +100,14 @@ en:
|
|
92
100
|
Error: %{stderr}
|
93
101
|
no_box_virtual_size: |-
|
94
102
|
No image virtual size specified for box.
|
103
|
+
no_disk_virtual_size: |-
|
104
|
+
No image virtual size specified for disk with index %{disk_index}.
|
95
105
|
no_box_format: |-
|
96
106
|
No image format specified for box.
|
97
107
|
wrong_box_format: |-
|
98
108
|
Wrong image format specified for box.
|
109
|
+
wrong_disk_format: |-
|
110
|
+
Wrong image format specified for disk with index %{disk_index}.
|
99
111
|
fog_libvirt_connection_error: |-
|
100
112
|
Error while connecting to Libvirt: %{error_message}
|
101
113
|
fog_create_volume_error: |-
|
data/spec/spec_helper.rb
CHANGED
@@ -31,5 +31,13 @@ require 'vagrant-libvirt'
|
|
31
31
|
require 'support/environment_helper'
|
32
32
|
require 'vagrant-spec/unit'
|
33
33
|
|
34
|
-
|
34
|
+
Dir[File.dirname(__FILE__) + '/support/**/*.rb'].each { |f| require f }
|
35
|
+
|
36
|
+
RSpec.configure do |config|
|
37
|
+
# ensure that setting of LIBVIRT_DEFAULT_URI in the environment is not picked
|
38
|
+
# up directly by tests, instead they must set as needed. Some build envs will
|
39
|
+
# may have it set to 'qemu:///session'.
|
40
|
+
config.before(:suite) do
|
41
|
+
ENV.delete('LIBVIRT_DEFAULT_URI')
|
42
|
+
end
|
35
43
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
##
|
2
|
+
# A simple extension of the Proc class that supports setting a custom binding
|
3
|
+
# and evaluates everything in the Proc using the new binding.
|
4
|
+
|
5
|
+
class ProcWithBinding < Proc
|
6
|
+
##
|
7
|
+
# Set the binding for this instance
|
8
|
+
|
9
|
+
def apply_binding(bind, *args)
|
10
|
+
@binding = bind
|
11
|
+
instance_exec(*args, &self)
|
12
|
+
end
|
13
|
+
|
14
|
+
def method_missing(method, *args)
|
15
|
+
begin
|
16
|
+
method_from_binding = eval("method(#{method.inspect})", @binding)
|
17
|
+
return method_from_binding.call(*args)
|
18
|
+
rescue NameError
|
19
|
+
# fall through on purpose
|
20
|
+
end
|
21
|
+
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require "rspec/expectations/version"
|
2
|
+
#
|
3
|
+
# Taken from https://github.com/cucumber/aruba/blob/main/lib/aruba/matchers/file/have_file_content.rb
|
4
|
+
# with minor modifications
|
5
|
+
#
|
6
|
+
# @!method have_file_content(content)
|
7
|
+
# This matchers checks if <file> has content. `content` can be a string,
|
8
|
+
# regexp or an RSpec matcher.
|
9
|
+
#
|
10
|
+
# @param [String, Regexp, Matcher] content
|
11
|
+
# Specifies the content of the file
|
12
|
+
#
|
13
|
+
# @return [Boolean] The result
|
14
|
+
#
|
15
|
+
# false:
|
16
|
+
# * if file does not exist
|
17
|
+
# * if file content is not equal string
|
18
|
+
# * if file content does not include regexp
|
19
|
+
# * if file content does not match the content specification
|
20
|
+
#
|
21
|
+
# true:
|
22
|
+
# * if file content includes regexp
|
23
|
+
# * if file content is equal string
|
24
|
+
# * if file content matches the content specification
|
25
|
+
#
|
26
|
+
# @example Use matcher with string
|
27
|
+
#
|
28
|
+
# RSpec.describe do
|
29
|
+
# it { expect(file1).to have_file_content('a') }
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# @example Use matcher with regexp
|
33
|
+
#
|
34
|
+
# RSpec.describe do
|
35
|
+
# it { expect(file1).to have_file_content(/a/) }
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# @example Use matcher with an RSpec matcher
|
39
|
+
#
|
40
|
+
# RSpec.describe do
|
41
|
+
# it { expect(file1).to have_file_content(a_string_starting_with 'a') }
|
42
|
+
# it { expect(files1).to include a_file_having_content(a_string_starting_with 'a') }
|
43
|
+
# end
|
44
|
+
RSpec::Matchers.define :have_file_content do |expected|
|
45
|
+
match do |actual|
|
46
|
+
next false unless File.exists?(actual)
|
47
|
+
|
48
|
+
@actual = File.read(actual).chomp
|
49
|
+
@expected = if expected.is_a? String
|
50
|
+
expected.chomp
|
51
|
+
else
|
52
|
+
expected
|
53
|
+
end
|
54
|
+
|
55
|
+
values_match?(@expected, @actual)
|
56
|
+
end
|
57
|
+
|
58
|
+
diffable if expected.is_a? String
|
59
|
+
|
60
|
+
description { "have file content: #{description_of expected}" }
|
61
|
+
end
|
62
|
+
|
63
|
+
RSpec::Matchers.alias_matcher :a_file_having_content, :have_file_content
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'support/sharedcontext'
|
3
|
+
|
4
|
+
require 'vagrant-libvirt/action/clean_machine_folder'
|
5
|
+
|
6
|
+
describe VagrantPlugins::ProviderLibvirt::Action::CleanMachineFolder do
|
7
|
+
subject { described_class.new(app, env) }
|
8
|
+
|
9
|
+
include_context 'unit'
|
10
|
+
|
11
|
+
describe '#call' do
|
12
|
+
before do
|
13
|
+
FileUtils.touch(File.join(machine.data_dir, "box.meta"))
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'with default options' do
|
17
|
+
it 'should verbosely remove the folder' do
|
18
|
+
expect(ui).to receive(:info).with('Deleting the machine folder')
|
19
|
+
|
20
|
+
expect(subject.call(env)).to be_nil
|
21
|
+
|
22
|
+
expect(File.exists?(machine.data_dir)).to eq(true)
|
23
|
+
expect(Dir.entries(machine.data_dir)).to match_array([".", ".."])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'when the data dir doesn\'t exist' do
|
28
|
+
before do
|
29
|
+
Dir.mktmpdir do |d|
|
30
|
+
# returns a temporary directory that has been already deleted when running
|
31
|
+
expect(machine).to receive(:data_dir).and_return(d.to_s).exactly(3).times
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should remove the folder' do
|
36
|
+
expect(ui).to receive(:info).with('Deleting the machine folder')
|
37
|
+
|
38
|
+
expect(subject.call(env)).to be_nil
|
39
|
+
|
40
|
+
expect(File.exists?(machine.data_dir)).to eq(true)
|
41
|
+
expect(Dir.entries(machine.data_dir)).to match_array([".", ".."])
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'with quiet option enabled' do
|
46
|
+
subject { described_class.new(app, env, {:quiet => true}) }
|
47
|
+
|
48
|
+
it 'should quietly remove the folder' do
|
49
|
+
expect(ui).to_not receive(:info).with('Deleting the machine folder')
|
50
|
+
|
51
|
+
expect(subject.call(env)).to be_nil
|
52
|
+
|
53
|
+
expect(File.exists?(machine.data_dir)).to eq(true)
|
54
|
+
expect(Dir.entries(machine.data_dir)).to match_array([".", ".."])
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -15,7 +15,8 @@ describe VagrantPlugins::ProviderLibvirt::Action::CreateDomain do
|
|
15
15
|
let(:servers) { double('servers') }
|
16
16
|
let(:volumes) { double('volumes') }
|
17
17
|
|
18
|
-
let(:
|
18
|
+
let(:domain_xml) { File.read(File.join(File.dirname(__FILE__), File.basename(__FILE__, '.rb'), domain_xml_file)) }
|
19
|
+
let(:storage_pool_xml) { File.read(File.join(File.dirname(__FILE__), File.basename(__FILE__, '.rb'), storage_pool_xml_file)) }
|
19
20
|
let(:libvirt_storage_pool) { double('storage_pool') }
|
20
21
|
|
21
22
|
describe '#call' do
|
@@ -31,6 +32,12 @@ describe VagrantPlugins::ProviderLibvirt::Action::CreateDomain do
|
|
31
32
|
|
32
33
|
env[:domain_name] = "vagrant-test_default"
|
33
34
|
|
35
|
+
env[:box_volumes] = []
|
36
|
+
env[:box_volumes].push({
|
37
|
+
:path=>"/test/box.img",
|
38
|
+
:name=>"test_vagrant_box_image_1.1.1_0.img",
|
39
|
+
:virtual_size=>5
|
40
|
+
})
|
34
41
|
# should be ignored for system session and used for user session
|
35
42
|
allow(Process).to receive(:uid).and_return(9999)
|
36
43
|
allow(Process).to receive(:gid).and_return(9999)
|
@@ -38,12 +45,13 @@ describe VagrantPlugins::ProviderLibvirt::Action::CreateDomain do
|
|
38
45
|
|
39
46
|
context 'connection => qemu:///system' do
|
40
47
|
context 'default pool' do
|
41
|
-
let(:
|
48
|
+
let(:domain_xml_file) { 'default_domain.xml' }
|
49
|
+
let(:storage_pool_xml_file) { 'default_system_storage_pool.xml' }
|
42
50
|
|
43
51
|
it 'should execute correctly' do
|
44
52
|
expect(libvirt_client).to receive(:lookup_storage_pool_by_name).and_return(libvirt_storage_pool)
|
45
53
|
expect(libvirt_storage_pool).to receive(:xml_desc).and_return(storage_pool_xml)
|
46
|
-
expect(servers).to receive(:create).and_return(machine)
|
54
|
+
expect(servers).to receive(:create).with(xml: domain_xml).and_return(machine)
|
47
55
|
expect(volumes).to_not receive(:create) # additional disks only
|
48
56
|
|
49
57
|
expect(subject.call(env)).to be_nil
|
@@ -72,6 +80,8 @@ describe VagrantPlugins::ProviderLibvirt::Action::CreateDomain do
|
|
72
80
|
end
|
73
81
|
|
74
82
|
context 'volume create succeeded' do
|
83
|
+
let(:domain_xml_file) { 'additional_disks_domain.xml' }
|
84
|
+
|
75
85
|
it 'should complete' do
|
76
86
|
expect(libvirt_client).to receive(:lookup_storage_pool_by_name).and_return(libvirt_storage_pool)
|
77
87
|
expect(libvirt_storage_pool).to receive(:xml_desc).and_return(storage_pool_xml)
|
@@ -83,7 +93,7 @@ describe VagrantPlugins::ProviderLibvirt::Action::CreateDomain do
|
|
83
93
|
:pool_name => "default",
|
84
94
|
)
|
85
95
|
)
|
86
|
-
expect(servers).to receive(:create).and_return(machine)
|
96
|
+
expect(servers).to receive(:create).with(xml: domain_xml).and_return(machine)
|
87
97
|
|
88
98
|
expect(subject.call(env)).to be_nil
|
89
99
|
end
|
@@ -113,7 +123,7 @@ describe VagrantPlugins::ProviderLibvirt::Action::CreateDomain do
|
|
113
123
|
end
|
114
124
|
|
115
125
|
context 'default pool' do
|
116
|
-
let(:
|
126
|
+
let(:storage_pool_xml_file) { 'default_user_storage_pool.xml' }
|
117
127
|
|
118
128
|
it 'should execute correctly' do
|
119
129
|
expect(libvirt_client).to receive(:lookup_storage_pool_by_name).and_return(libvirt_storage_pool)
|
@@ -0,0 +1,54 @@
|
|
1
|
+
<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
|
2
|
+
<name>vagrant-test_default</name>
|
3
|
+
<title></title>
|
4
|
+
<description>Source: /rootpath/Vagrantfile</description>
|
5
|
+
<uuid></uuid>
|
6
|
+
<memory>524288</memory>
|
7
|
+
<vcpu>1</vcpu>
|
8
|
+
|
9
|
+
|
10
|
+
<cpu mode='host-model'>
|
11
|
+
<model fallback='allow'></model>
|
12
|
+
</cpu>
|
13
|
+
|
14
|
+
|
15
|
+
<os>
|
16
|
+
<type>hvm</type>
|
17
|
+
<kernel></kernel>
|
18
|
+
<initrd></initrd>
|
19
|
+
<cmdline></cmdline>
|
20
|
+
</os>
|
21
|
+
<features>
|
22
|
+
<acpi/>
|
23
|
+
<apic/>
|
24
|
+
<pae/>
|
25
|
+
</features>
|
26
|
+
<clock offset='utc'>
|
27
|
+
</clock>
|
28
|
+
<devices>
|
29
|
+
<disk type='file' device='disk'>
|
30
|
+
<driver name='qemu' type='qcow2' cache='default'/>
|
31
|
+
<source file='/var/lib/libvirt/images/vagrant-test_default-vdb.qcow2'/>
|
32
|
+
<target dev='vdb' bus='virtio'/>
|
33
|
+
</disk>
|
34
|
+
|
35
|
+
|
36
|
+
<serial type='pty'>
|
37
|
+
<target port='0'/>
|
38
|
+
</serial>
|
39
|
+
<console type='pty'>
|
40
|
+
<target port='0'/>
|
41
|
+
</console>
|
42
|
+
|
43
|
+
|
44
|
+
<input type='mouse' bus='ps2'/>
|
45
|
+
|
46
|
+
<graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1' keymap='en-us' />
|
47
|
+
<video>
|
48
|
+
<model type='cirrus' vram='9216' heads='1'/>
|
49
|
+
</video>
|
50
|
+
|
51
|
+
|
52
|
+
</devices>
|
53
|
+
|
54
|
+
</domain>
|