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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +251 -33
  3. data/lib/vagrant-libvirt/action.rb +7 -1
  4. data/lib/vagrant-libvirt/action/clean_machine_folder.rb +30 -0
  5. data/lib/vagrant-libvirt/action/create_domain.rb +28 -11
  6. data/lib/vagrant-libvirt/action/create_domain_volume.rb +57 -55
  7. data/lib/vagrant-libvirt/action/create_network_interfaces.rb +0 -3
  8. data/lib/vagrant-libvirt/action/create_networks.rb +11 -4
  9. data/lib/vagrant-libvirt/action/destroy_domain.rb +1 -1
  10. data/lib/vagrant-libvirt/action/forward_ports.rb +36 -37
  11. data/lib/vagrant-libvirt/action/halt_domain.rb +25 -9
  12. data/lib/vagrant-libvirt/action/handle_box_image.rb +170 -77
  13. data/lib/vagrant-libvirt/action/is_running.rb +1 -3
  14. data/lib/vagrant-libvirt/action/is_suspended.rb +4 -4
  15. data/lib/vagrant-libvirt/action/set_boot_order.rb +6 -2
  16. data/lib/vagrant-libvirt/action/wait_till_up.rb +1 -25
  17. data/lib/vagrant-libvirt/cap/{mount_p9.rb → mount_9p.rb} +2 -2
  18. data/lib/vagrant-libvirt/cap/mount_virtiofs.rb +37 -0
  19. data/lib/vagrant-libvirt/cap/{synced_folder.rb → synced_folder_9p.rb} +4 -5
  20. data/lib/vagrant-libvirt/cap/synced_folder_virtiofs.rb +109 -0
  21. data/lib/vagrant-libvirt/config.rb +34 -2
  22. data/lib/vagrant-libvirt/driver.rb +3 -1
  23. data/lib/vagrant-libvirt/errors.rb +24 -1
  24. data/lib/vagrant-libvirt/plugin.rb +14 -5
  25. data/lib/vagrant-libvirt/templates/domain.xml.erb +7 -6
  26. data/lib/vagrant-libvirt/templates/private_network.xml.erb +1 -1
  27. data/lib/vagrant-libvirt/util/byte_number.rb +71 -0
  28. data/lib/vagrant-libvirt/util/network_util.rb +21 -3
  29. data/lib/vagrant-libvirt/version +1 -1
  30. data/locales/en.yml +12 -0
  31. data/spec/spec_helper.rb +9 -1
  32. data/spec/support/binding_proc.rb +24 -0
  33. data/spec/support/matchers/have_file_content.rb +63 -0
  34. data/spec/unit/action/clean_machine_folder_spec.rb +58 -0
  35. data/spec/unit/action/create_domain_spec.rb +15 -5
  36. data/spec/unit/action/create_domain_spec/additional_disks_domain.xml +54 -0
  37. data/spec/unit/action/create_domain_spec/default_domain.xml +49 -0
  38. data/spec/unit/action/create_domain_volume_spec.rb +104 -0
  39. data/spec/unit/action/create_domain_volume_spec/one_disk_in_storage.xml +21 -0
  40. data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_0.xml +21 -0
  41. data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_1.xml +21 -0
  42. data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_2.xml +21 -0
  43. data/spec/unit/action/destroy_domain_spec.rb +1 -1
  44. data/spec/unit/action/forward_ports_spec.rb +202 -0
  45. data/spec/unit/action/halt_domain_spec.rb +90 -0
  46. data/spec/unit/action/handle_box_image_spec.rb +441 -0
  47. data/spec/unit/action/wait_till_up_spec.rb +11 -15
  48. data/spec/unit/config_spec.rb +12 -9
  49. data/spec/unit/templates/domain_all_settings.xml +8 -0
  50. data/spec/unit/templates/domain_spec.rb +20 -1
  51. data/spec/unit/util/byte_number_spec.rb +26 -0
  52. metadata +52 -18
@@ -0,0 +1,49 @@
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
+
30
+
31
+ <serial type='pty'>
32
+ <target port='0'/>
33
+ </serial>
34
+ <console type='pty'>
35
+ <target port='0'/>
36
+ </console>
37
+
38
+
39
+ <input type='mouse' bus='ps2'/>
40
+
41
+ <graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1' keymap='en-us' />
42
+ <video>
43
+ <model type='cirrus' vram='9216' heads='1'/>
44
+ </video>
45
+
46
+
47
+ </devices>
48
+
49
+ </domain>
@@ -0,0 +1,104 @@
1
+ require 'spec_helper'
2
+ require 'support/sharedcontext'
3
+ require 'support/libvirt_context'
4
+
5
+ require 'vagrant-libvirt/action/destroy_domain'
6
+ require 'vagrant-libvirt/util/byte_number'
7
+
8
+
9
+ describe VagrantPlugins::ProviderLibvirt::Action::CreateDomainVolume do
10
+ subject { described_class.new(app, env) }
11
+
12
+ include_context 'unit'
13
+ include_context 'libvirt'
14
+
15
+ let(:libvirt_domain) { double('libvirt_domain') }
16
+ let(:libvirt_client) { double('libvirt_client') }
17
+ let(:volumes) { double('volumes') }
18
+ let(:all) { double('all') }
19
+ let(:box_volume) { double('box_volume') }
20
+
21
+ def read_test_file(name)
22
+ File.read(File.join(File.dirname(__FILE__), File.basename(__FILE__, '.rb'), name))
23
+ end
24
+
25
+ describe '#call' do
26
+ before do
27
+ allow_any_instance_of(VagrantPlugins::ProviderLibvirt::Driver)
28
+ .to receive(:connection).and_return(connection)
29
+ allow(connection).to receive(:client).and_return(libvirt_client)
30
+ allow(connection).to receive(:volumes).and_return(volumes)
31
+ allow(volumes).to receive(:all).and_return(all)
32
+ allow(all).to receive(:first).and_return(box_volume)
33
+ allow(box_volume).to receive(:id).and_return(nil)
34
+ env[:domain_name] = 'test'
35
+ end
36
+
37
+ context 'when one disk' do
38
+ before do
39
+ allow(box_volume).to receive(:path).and_return('/test/path_0.img')
40
+ env[:box_volumes] = [
41
+ {
42
+ :name=>"test_vagrant_box_image_1.1.1_0.img",
43
+ :virtual_size=>ByteNumber.new(5368709120)
44
+ }
45
+ ]
46
+ end
47
+
48
+ it 'should create one disk in storage' do
49
+ expected_xml = read_test_file('one_disk_in_storage.xml')
50
+ expect(ui).to receive(:info).with('Creating image (snapshot of base box volume).')
51
+ expect(logger).to receive(:debug).with('Using pool default for base box snapshot')
52
+ expect(volumes).to receive(:create).with(
53
+ :xml => expected_xml,
54
+ :pool_name => "default"
55
+ )
56
+ expect(subject.call(env)).to be_nil
57
+ end
58
+ end
59
+
60
+ context 'when three disks' do
61
+ before do
62
+ allow(box_volume).to receive(:path).and_return(
63
+ '/test/path_0.img',
64
+ '/test/path_1.img',
65
+ '/test/path_2.img',
66
+ )
67
+ env[:box_volumes] = [
68
+ {
69
+ :name=>"test_vagrant_box_image_1.1.1_0.img",
70
+ :virtual_size=>ByteNumber.new(5368709120)
71
+ },
72
+ {
73
+ :name=>"test_vagrant_box_image_1.1.1_1.img",
74
+ :virtual_size=>ByteNumber.new(10737423360)
75
+ },
76
+ {
77
+ :name=>"test_vagrant_box_image_1.1.1_2.img",
78
+ :virtual_size=>ByteNumber.new(21474836480)
79
+ }
80
+ ]
81
+ end
82
+
83
+ it 'should create three disks in storage' do
84
+ expect(ui).to receive(:info).with('Creating image (snapshot of base box volume).')
85
+ expect(logger).to receive(:debug).with('Using pool default for base box snapshot')
86
+ expect(volumes).to receive(:create).with(
87
+ :xml => read_test_file('three_disks_in_storage_disk_0.xml'),
88
+ :pool_name => "default"
89
+ )
90
+ expect(logger).to receive(:debug).with('Using pool default for base box snapshot')
91
+ expect(volumes).to receive(:create).with(
92
+ :xml => read_test_file('three_disks_in_storage_disk_1.xml'),
93
+ :pool_name => "default"
94
+ )
95
+ expect(logger).to receive(:debug).with('Using pool default for base box snapshot')
96
+ expect(volumes).to receive(:create).with(
97
+ :xml => read_test_file('three_disks_in_storage_disk_2.xml'),
98
+ :pool_name => "default"
99
+ )
100
+ expect(subject.call(env)).to be_nil
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,21 @@
1
+ <volume>
2
+ <name>test.img</name>
3
+ <capacity unit="B">5368709120</capacity>
4
+ <target>
5
+ <format type="qcow2"></format>
6
+ <permissions>
7
+ <owner>0</owner>
8
+ <group>0</group>
9
+ <label>virt_image_t</label>
10
+ </permissions>
11
+ </target>
12
+ <backingStore>
13
+ <path>/test/path_0.img</path>
14
+ <format type="qcow2"></format>
15
+ <permissions>
16
+ <owner>0</owner>
17
+ <group>0</group>
18
+ <label>virt_image_t</label>
19
+ </permissions>
20
+ </backingStore>
21
+ </volume>
@@ -0,0 +1,21 @@
1
+ <volume>
2
+ <name>test.img</name>
3
+ <capacity unit="B">5368709120</capacity>
4
+ <target>
5
+ <format type="qcow2"></format>
6
+ <permissions>
7
+ <owner>0</owner>
8
+ <group>0</group>
9
+ <label>virt_image_t</label>
10
+ </permissions>
11
+ </target>
12
+ <backingStore>
13
+ <path>/test/path_0.img</path>
14
+ <format type="qcow2"></format>
15
+ <permissions>
16
+ <owner>0</owner>
17
+ <group>0</group>
18
+ <label>virt_image_t</label>
19
+ </permissions>
20
+ </backingStore>
21
+ </volume>
@@ -0,0 +1,21 @@
1
+ <volume>
2
+ <name>test_1.img</name>
3
+ <capacity unit="B">10737423360</capacity>
4
+ <target>
5
+ <format type="qcow2"></format>
6
+ <permissions>
7
+ <owner>0</owner>
8
+ <group>0</group>
9
+ <label>virt_image_t</label>
10
+ </permissions>
11
+ </target>
12
+ <backingStore>
13
+ <path>/test/path_1.img</path>
14
+ <format type="qcow2"></format>
15
+ <permissions>
16
+ <owner>0</owner>
17
+ <group>0</group>
18
+ <label>virt_image_t</label>
19
+ </permissions>
20
+ </backingStore>
21
+ </volume>
@@ -0,0 +1,21 @@
1
+ <volume>
2
+ <name>test_2.img</name>
3
+ <capacity unit="B">21474836480</capacity>
4
+ <target>
5
+ <format type="qcow2"></format>
6
+ <permissions>
7
+ <owner>0</owner>
8
+ <group>0</group>
9
+ <label>virt_image_t</label>
10
+ </permissions>
11
+ </target>
12
+ <backingStore>
13
+ <path>/test/path_2.img</path>
14
+ <format type="qcow2"></format>
15
+ <permissions>
16
+ <owner>0</owner>
17
+ <group>0</group>
18
+ <label>virt_image_t</label>
19
+ </permissions>
20
+ </backingStore>
21
+ </volume>
@@ -85,7 +85,7 @@ describe VagrantPlugins::ProviderLibvirt::Action::DestroyDomain do
85
85
 
86
86
  it 'uses explicit removal of disks' do
87
87
  allow(libvirt_domain).to receive(:name).and_return('test')
88
- allow(domain).to receive(:volumes).and_return([root_disk])
88
+ allow(domain).to receive(:volumes).and_return([root_disk, nil])
89
89
 
90
90
  expect(domain).to_not receive(:destroy).with(destroy_volumes: true)
91
91
  expect(root_disk).to receive(:destroy) # root disk remove
@@ -0,0 +1,202 @@
1
+ require 'spec_helper'
2
+ require 'support/sharedcontext'
3
+ require 'support/libvirt_context'
4
+
5
+ require 'vagrant-libvirt/errors'
6
+ require 'vagrant-libvirt/action/forward_ports'
7
+
8
+ describe VagrantPlugins::ProviderLibvirt::Action::ForwardPorts do
9
+ subject { described_class.new(app, env) }
10
+
11
+ include_context 'unit'
12
+
13
+ let(:machine_config) { double("machine_config") }
14
+ let(:vm_config) { double("vm_config") }
15
+ let(:provider_config) { double("provider_config") }
16
+
17
+ before (:each) do
18
+ allow(machine).to receive(:config).and_return(machine_config)
19
+ allow(machine).to receive(:provider_config).and_return(provider_config)
20
+ allow(machine_config).to receive(:vm).and_return(vm_config)
21
+ allow(vm_config).to receive(:networks).and_return([])
22
+ allow(provider_config).to receive(:forward_ssh_port).and_return(false)
23
+ end
24
+
25
+ describe '#call' do
26
+ context 'with none defined' do
27
+ it 'should skip calling forward_ports' do
28
+ expect(subject).to_not receive(:forward_ports)
29
+ expect(subject.call(env)).to be_nil
30
+ end
31
+ end
32
+
33
+ context 'with network including one forwarded port' do
34
+ let(:networks) { [
35
+ [:private_network, {:ip=>"10.20.30.40", :protocol=>"tcp", :id=>"6b8175ed-3220-4b63-abaf-0bb8d7cdd723"}],
36
+ [:forwarded_port, port_options],
37
+ ]}
38
+
39
+ let(:port_options){ {guest: 80, host: 8080} }
40
+
41
+ it 'should compile a single port forward to set up' do
42
+ expect(vm_config).to receive(:networks).and_return(networks)
43
+ expect(ui).to_not receive(:warn)
44
+ expect(subject).to receive(:forward_ports).and_return(nil)
45
+
46
+ expect(subject.call(env)).to be_nil
47
+
48
+ expect(env[:forwarded_ports]).to eq([networks[1][1]])
49
+ end
50
+
51
+ context 'when host port in protected range' do
52
+ let(:port_options){ {guest: 8080, host: 80} }
53
+
54
+ it 'should emit a warning' do
55
+ expect(vm_config).to receive(:networks).and_return(networks)
56
+ expect(ui).to receive(:warn).with(include("You are trying to forward to privileged ports"))
57
+ expect(subject).to receive(:forward_ports).and_return(nil)
58
+
59
+ expect(subject.call(env)).to be_nil
60
+ end
61
+ end
62
+ end
63
+
64
+ context 'when udp protocol is selected' do
65
+ let(:port_options){ {guest: 80, host: 8080, protocol: "udp"} }
66
+
67
+ it 'should skip and emit warning' do
68
+ expect(vm_config).to receive(:networks).and_return([[:forwarded_port, port_options]])
69
+ expect(ui).to receive(:warn).with("Forwarding UDP ports is not supported. Ignoring.")
70
+ expect(subject).to_not receive(:forward_ports)
71
+
72
+ expect(subject.call(env)).to be_nil
73
+ end
74
+ end
75
+
76
+ context 'when default ssh port forward provided' do
77
+ let(:networks){ [
78
+ [:private_network, {:ip=>"10.20.30.40", :protocol=>"tcp", :id=>"6b8175ed-3220-4b63-abaf-0bb8d7cdd723"}],
79
+ [:forwarded_port, {guest: 80, host: 8080}],
80
+ [:forwarded_port, {guest: 22, host: 2222, host_ip: '127.0.0.1', id: 'ssh'}],
81
+ ]}
82
+
83
+ context 'with default config' do
84
+ it 'should not forward the ssh port' do
85
+ expect(vm_config).to receive(:networks).and_return(networks)
86
+ expect(subject).to receive(:forward_ports)
87
+
88
+ expect(subject.call(env)).to be_nil
89
+
90
+ expect(env[:forwarded_ports]).to eq([networks[1][1]])
91
+ end
92
+ end
93
+
94
+ context 'with forward_ssh_port enabled' do
95
+ before do
96
+ allow(provider_config).to receive(:forward_ssh_port).and_return(true)
97
+ end
98
+
99
+ it 'should forward the port' do
100
+ expect(vm_config).to receive(:networks).and_return(networks)
101
+ expect(subject).to receive(:forward_ports)
102
+
103
+ expect(subject.call(env)).to be_nil
104
+
105
+ expect(env[:forwarded_ports]).to eq(networks.drop(1).map { |_, opts| opts })
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ describe '#forward_ports' do
112
+ let(:pid_dir){ machine.data_dir.join('pids') }
113
+
114
+ before (:each) do
115
+ allow(env).to receive(:[]).and_call_original
116
+ allow(machine).to receive(:ssh_info).and_return(
117
+ {
118
+ :host => "localhost",
119
+ :username => "vagrant",
120
+ :port => 22,
121
+ :private_key_path => ["/home/test/.ssh/id_rsa"],
122
+ }
123
+ )
124
+ allow(provider_config).to receive(:proxy_command).and_return(nil)
125
+ end
126
+
127
+ context 'with port to forward' do
128
+ let(:port_options){ {guest: 80, host: 8080, guest_ip: "192.168.1.121"} }
129
+
130
+ it 'should spawn ssh to setup forwarding' do
131
+ expect(env).to receive(:[]).with(:forwarded_ports).and_return([port_options])
132
+ expect(ui).to receive(:info).with("#{port_options[:guest]} (guest) => #{port_options[:host]} (host) (adapter eth0)")
133
+ expect(subject).to receive(:spawn).with(/ssh -n -o User=vagrant -o Port=22.*-L \*:8080:192.168.1.121:80 -N localhost/, anything).and_return(9999)
134
+
135
+ expect(subject.forward_ports(env)).to eq([port_options])
136
+
137
+ expect(pid_dir.join('ssh_8080.pid')).to have_file_content("9999")
138
+ end
139
+ end
140
+
141
+ context 'with privileged host port' do
142
+ let(:port_options){ {guest: 80, host: 80, guest_ip: "192.168.1.121"} }
143
+
144
+ it 'should spawn ssh to setup forwarding' do
145
+ expect(env).to receive(:[]).with(:forwarded_ports).and_return([port_options])
146
+ expect(ui).to receive(:info).with("#{port_options[:guest]} (guest) => #{port_options[:host]} (host) (adapter eth0)")
147
+ expect(ui).to receive(:info).with('Requesting sudo for host port(s) <= 1024')
148
+ expect(subject).to receive(:system).with('sudo -v').and_return(true)
149
+ expect(subject).to receive(:spawn).with(/sudo ssh -n -o User=vagrant -o Port=22.*-L \*:80:192.168.1.121:80 -N localhost/, anything).and_return(10000)
150
+
151
+ expect(subject.forward_ports(env)).to eq([port_options])
152
+
153
+ expect(pid_dir.join('ssh_80.pid')).to have_file_content("10000")
154
+ end
155
+ end
156
+ end
157
+ end
158
+
159
+ describe VagrantPlugins::ProviderLibvirt::Action::ClearForwardedPorts do
160
+ subject { described_class.new(app, env) }
161
+
162
+ include_context 'unit'
163
+ include_context 'libvirt'
164
+
165
+ describe '#call' do
166
+ context 'no forwarded ports' do
167
+ it 'should skip checking if pids are running' do
168
+ expect(subject).to_not receive(:ssh_pid?)
169
+ expect(logger).to receive(:info).with('No ssh pids found')
170
+
171
+ expect(subject.call(env)).to be_nil
172
+ end
173
+ end
174
+
175
+ context 'multiple forwarded ports' do
176
+ before do
177
+ data_dir = machine.data_dir.join('pids')
178
+ data_dir.mkdir unless data_dir.directory?
179
+
180
+ [
181
+ {:port => '8080', :pid => '10001'},
182
+ {:port => '8081', :pid => '10002'},
183
+ ].each do |port_pid|
184
+ File.write(data_dir.to_s + "/ssh_#{port_pid[:port]}.pid", port_pid[:pid])
185
+ end
186
+ end
187
+ it 'should terminate each of the processes' do
188
+ expect(logger).to receive(:info).with(no_args) # don't know how to test translations from vagrant
189
+ expect(subject).to receive(:ssh_pid?).with("10001").and_return(true)
190
+ expect(subject).to receive(:ssh_pid?).with("10002").and_return(true)
191
+ expect(logger).to receive(:debug).with(/Killing pid/).twice()
192
+ expect(logger).to receive(:info).with('Removing ssh pid files')
193
+ expect(subject).to receive(:system).with("kill 10001")
194
+ expect(subject).to receive(:system).with("kill 10002")
195
+
196
+ expect(subject.call(env)).to be_nil
197
+
198
+ expect(Dir.entries(machine.data_dir.join('pids'))).to match_array(['.', '..'])
199
+ end
200
+ end
201
+ end
202
+ end