vagrant-libvirt 0.1.2 → 0.5.0

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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +530 -100
  3. data/lib/vagrant-libvirt/action.rb +7 -1
  4. data/lib/vagrant-libvirt/action/clean_machine_folder.rb +28 -0
  5. data/lib/vagrant-libvirt/action/create_domain.rb +78 -22
  6. data/lib/vagrant-libvirt/action/create_domain_volume.rb +57 -57
  7. data/lib/vagrant-libvirt/action/create_network_interfaces.rb +1 -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 +40 -40
  11. data/lib/vagrant-libvirt/action/halt_domain.rb +25 -9
  12. data/lib/vagrant-libvirt/action/handle_box_image.rb +163 -72
  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/package_domain.rb +10 -4
  16. data/lib/vagrant-libvirt/action/start_domain.rb +86 -29
  17. data/lib/vagrant-libvirt/action/wait_till_up.rb +8 -52
  18. data/lib/vagrant-libvirt/cap/{mount_p9.rb → mount_9p.rb} +2 -2
  19. data/lib/vagrant-libvirt/cap/mount_virtiofs.rb +37 -0
  20. data/lib/vagrant-libvirt/cap/public_address.rb +16 -0
  21. data/lib/vagrant-libvirt/cap/{synced_folder.rb → synced_folder_9p.rb} +4 -5
  22. data/lib/vagrant-libvirt/cap/synced_folder_virtiofs.rb +109 -0
  23. data/lib/vagrant-libvirt/config.rb +257 -34
  24. data/lib/vagrant-libvirt/driver.rb +49 -32
  25. data/lib/vagrant-libvirt/errors.rb +24 -1
  26. data/lib/vagrant-libvirt/plugin.rb +19 -5
  27. data/lib/vagrant-libvirt/provider.rb +2 -9
  28. data/lib/vagrant-libvirt/templates/domain.xml.erb +40 -10
  29. data/lib/vagrant-libvirt/templates/private_network.xml.erb +1 -1
  30. data/lib/vagrant-libvirt/templates/public_interface.xml.erb +5 -1
  31. data/lib/vagrant-libvirt/util.rb +1 -0
  32. data/lib/vagrant-libvirt/util/erb_template.rb +6 -7
  33. data/lib/vagrant-libvirt/util/network_util.rb +21 -3
  34. data/lib/vagrant-libvirt/util/ui.rb +23 -0
  35. data/lib/vagrant-libvirt/version +1 -0
  36. data/lib/vagrant-libvirt/version.rb +72 -1
  37. data/locales/en.yml +12 -0
  38. data/spec/spec_helper.rb +37 -3
  39. data/spec/support/binding_proc.rb +24 -0
  40. data/spec/support/libvirt_context.rb +3 -1
  41. data/spec/support/matchers/have_file_content.rb +63 -0
  42. data/spec/support/sharedcontext.rb +7 -3
  43. data/spec/unit/action/clean_machine_folder_spec.rb +48 -0
  44. data/spec/unit/action/create_domain_spec.rb +166 -0
  45. data/spec/unit/action/create_domain_spec/default_system_storage_pool.xml +17 -0
  46. data/spec/unit/action/create_domain_spec/default_user_storage_pool.xml +17 -0
  47. data/spec/unit/action/create_domain_volume_spec.rb +102 -0
  48. data/spec/unit/action/create_domain_volume_spec/one_disk_in_storage.xml +21 -0
  49. data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_0.xml +21 -0
  50. data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_1.xml +21 -0
  51. data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_2.xml +21 -0
  52. data/spec/unit/action/destroy_domain_spec.rb +3 -3
  53. data/spec/unit/action/forward_ports_spec.rb +202 -0
  54. data/spec/unit/action/halt_domain_spec.rb +90 -0
  55. data/spec/unit/action/handle_box_image_spec.rb +363 -0
  56. data/spec/unit/action/set_name_of_domain_spec.rb +2 -2
  57. data/spec/unit/action/start_domain_spec.rb +231 -0
  58. data/spec/unit/action/start_domain_spec/clock_timer_rtc.xml +50 -0
  59. data/spec/unit/action/start_domain_spec/default.xml +48 -0
  60. data/spec/unit/action/start_domain_spec/default_added_tpm_path.xml +48 -0
  61. data/spec/unit/action/start_domain_spec/default_added_tpm_version.xml +48 -0
  62. data/spec/unit/action/wait_till_up_spec.rb +22 -21
  63. data/spec/unit/config_spec.rb +438 -0
  64. data/spec/unit/provider_spec.rb +11 -0
  65. data/spec/unit/templates/domain_all_settings.xml +16 -3
  66. data/spec/unit/templates/domain_custom_cpu_model.xml +4 -1
  67. data/spec/unit/templates/domain_defaults.xml +4 -1
  68. data/spec/unit/templates/domain_spec.rb +102 -3
  69. data/spec/unit/templates/tpm/version_1.2.xml +54 -0
  70. data/spec/unit/templates/tpm/version_2.0.xml +53 -0
  71. metadata +108 -16
  72. data/lib/vagrant-libvirt/action/halt_confirm.rb +0 -20
@@ -0,0 +1,17 @@
1
+ <pool type='dir'>
2
+ <name>default</name>
3
+ <uuid>434e1b75-4a72-45d7-8a98-ebd90c125d22</uuid>
4
+ <capacity unit='bytes'>10737418240</capacity>
5
+ <allocation unit='bytes'>10737418240</allocation>
6
+ <available unit='bytes'>10737418240</available>
7
+ <source>
8
+ </source>
9
+ <target>
10
+ <path>/var/lib/libvirt/images</path>
11
+ <permissions>
12
+ <mode>0755</mode>
13
+ <owner>0</owner>
14
+ <group>0</group>
15
+ </permissions>
16
+ </target>
17
+ </pool>
@@ -0,0 +1,17 @@
1
+ <pool type='dir'>
2
+ <name>default</name>
3
+ <uuid>434e1b75-4a72-45d7-8a98-ebd90c125d22</uuid>
4
+ <capacity unit='bytes'>10737418240</capacity>
5
+ <allocation unit='bytes'>10737418240</allocation>
6
+ <available unit='bytes'>10737418240</available>
7
+ <source>
8
+ </source>
9
+ <target>
10
+ <path>/var/lib/libvirt/images</path>
11
+ <permissions>
12
+ <mode>0755</mode>
13
+ <owner>0</owner>
14
+ <group>0</group>
15
+ </permissions>
16
+ </target>
17
+ </pool>
@@ -0,0 +1,102 @@
1
+ require 'spec_helper'
2
+ require 'support/sharedcontext'
3
+ require 'support/libvirt_context'
4
+
5
+ require 'vagrant-libvirt/action/destroy_domain'
6
+
7
+ describe VagrantPlugins::ProviderLibvirt::Action::CreateDomainVolume do
8
+ subject { described_class.new(app, env) }
9
+
10
+ include_context 'unit'
11
+ include_context 'libvirt'
12
+
13
+ let(:libvirt_domain) { double('libvirt_domain') }
14
+ let(:libvirt_client) { double('libvirt_client') }
15
+ let(:volumes) { double('volumes') }
16
+ let(:all) { double('all') }
17
+ let(:box_volume) { double('box_volume') }
18
+
19
+ def read_test_file(name)
20
+ File.read(File.join(File.dirname(__FILE__), File.basename(__FILE__, '.rb'), name))
21
+ end
22
+
23
+ describe '#call' do
24
+ before do
25
+ allow_any_instance_of(VagrantPlugins::ProviderLibvirt::Driver)
26
+ .to receive(:connection).and_return(connection)
27
+ allow(connection).to receive(:client).and_return(libvirt_client)
28
+ allow(connection).to receive(:volumes).and_return(volumes)
29
+ allow(volumes).to receive(:all).and_return(all)
30
+ allow(all).to receive(:first).and_return(box_volume)
31
+ allow(box_volume).to receive(:id).and_return(nil)
32
+ env[:domain_name] = 'test'
33
+ end
34
+
35
+ context 'when one disk' do
36
+ before do
37
+ allow(box_volume).to receive(:path).and_return('/test/path_0.img')
38
+ env[:box_volumes] = [
39
+ {
40
+ :name=>"test_vagrant_box_image_1.1.1_0.img",
41
+ :virtual_size=>5
42
+ }
43
+ ]
44
+ end
45
+
46
+ it 'should create one disk in storage' do
47
+ expected_xml = read_test_file('one_disk_in_storage.xml')
48
+ expect(ui).to receive(:info).with('Creating image (snapshot of base box volume).')
49
+ expect(logger).to receive(:debug).with('Using pool default for base box snapshot')
50
+ expect(volumes).to receive(:create).with(
51
+ :xml => expected_xml,
52
+ :pool_name => "default"
53
+ )
54
+ expect(subject.call(env)).to be_nil
55
+ end
56
+ end
57
+
58
+ context 'when three disks' do
59
+ before do
60
+ allow(box_volume).to receive(:path).and_return(
61
+ '/test/path_0.img',
62
+ '/test/path_1.img',
63
+ '/test/path_2.img',
64
+ )
65
+ env[:box_volumes] = [
66
+ {
67
+ :name=>"test_vagrant_box_image_1.1.1_0.img",
68
+ :virtual_size=>5
69
+ },
70
+ {
71
+ :name=>"test_vagrant_box_image_1.1.1_1.img",
72
+ :virtual_size=>10
73
+ },
74
+ {
75
+ :name=>"test_vagrant_box_image_1.1.1_2.img",
76
+ :virtual_size=>20
77
+ }
78
+ ]
79
+ end
80
+
81
+ it 'should create three disks in storage' do
82
+ expect(ui).to receive(:info).with('Creating image (snapshot of base box volume).')
83
+ expect(logger).to receive(:debug).with('Using pool default for base box snapshot')
84
+ expect(volumes).to receive(:create).with(
85
+ :xml => read_test_file('three_disks_in_storage_disk_0.xml'),
86
+ :pool_name => "default"
87
+ )
88
+ expect(logger).to receive(:debug).with('Using pool default for base box snapshot')
89
+ expect(volumes).to receive(:create).with(
90
+ :xml => read_test_file('three_disks_in_storage_disk_1.xml'),
91
+ :pool_name => "default"
92
+ )
93
+ expect(logger).to receive(:debug).with('Using pool default for base box snapshot')
94
+ expect(volumes).to receive(:create).with(
95
+ :xml => read_test_file('three_disks_in_storage_disk_2.xml'),
96
+ :pool_name => "default"
97
+ )
98
+ expect(subject.call(env)).to be_nil
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,21 @@
1
+ <volume>
2
+ <name>test.img</name>
3
+ <capacity unit="G">5</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="G">5</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="G">10</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="G">20</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>
@@ -33,7 +33,7 @@ describe VagrantPlugins::ProviderLibvirt::Action::DestroyDomain do
33
33
  before do
34
34
  allow(libvirt_domain).to receive(:list_snapshots).and_return([])
35
35
  allow(libvirt_domain).to receive(:has_managed_save?).and_return(nil)
36
- root_disk.stub(name: 'test.img')
36
+ allow(root_disk).to receive(:name).and_return('test.img')
37
37
  end
38
38
 
39
39
  context 'when only has root disk' do
@@ -57,7 +57,7 @@ describe VagrantPlugins::ProviderLibvirt::Action::DestroyDomain do
57
57
 
58
58
  let(:extra_disk) { double('libvirt_extra_disk') }
59
59
  before do
60
- extra_disk.stub(name: 'test-vdb.qcow2')
60
+ allow(extra_disk).to receive(:name).and_return('test-vdb.qcow2')
61
61
  end
62
62
 
63
63
  it 'destroys disks individually' do
@@ -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