vagrant-libvirt 0.3.0 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +421 -50
  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 +56 -18
  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 +37 -38
  11. data/lib/vagrant-libvirt/action/halt_domain.rb +25 -9
  12. data/lib/vagrant-libvirt/action/handle_box_image.rb +163 -74
  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 +2 -1
  16. data/lib/vagrant-libvirt/action/set_boot_order.rb +6 -2
  17. data/lib/vagrant-libvirt/action/start_domain.rb +86 -29
  18. data/lib/vagrant-libvirt/action/wait_till_up.rb +8 -52
  19. data/lib/vagrant-libvirt/cap/{mount_p9.rb → mount_9p.rb} +2 -2
  20. data/lib/vagrant-libvirt/cap/mount_virtiofs.rb +37 -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 +236 -43
  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 +14 -5
  27. data/lib/vagrant-libvirt/provider.rb +2 -9
  28. data/lib/vagrant-libvirt/templates/domain.xml.erb +35 -10
  29. data/lib/vagrant-libvirt/templates/private_network.xml.erb +1 -1
  30. data/lib/vagrant-libvirt/util/network_util.rb +21 -3
  31. data/lib/vagrant-libvirt/version +1 -1
  32. data/lib/vagrant-libvirt/version.rb +57 -9
  33. data/locales/en.yml +12 -0
  34. data/spec/spec_helper.rb +37 -3
  35. data/spec/support/binding_proc.rb +24 -0
  36. data/spec/support/libvirt_context.rb +2 -0
  37. data/spec/support/matchers/have_file_content.rb +63 -0
  38. data/spec/support/sharedcontext.rb +4 -0
  39. data/spec/unit/action/clean_machine_folder_spec.rb +58 -0
  40. data/spec/unit/action/create_domain_spec.rb +121 -36
  41. data/spec/unit/action/create_domain_spec/additional_disks_domain.xml +54 -0
  42. data/spec/unit/action/create_domain_spec/default_domain.xml +49 -0
  43. data/spec/unit/action/create_domain_spec/{default_storage_pool.xml → default_system_storage_pool.xml} +0 -0
  44. data/spec/unit/action/create_domain_spec/default_user_storage_pool.xml +17 -0
  45. data/spec/unit/action/create_domain_volume_spec.rb +102 -0
  46. data/spec/unit/action/create_domain_volume_spec/one_disk_in_storage.xml +21 -0
  47. data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_0.xml +21 -0
  48. data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_1.xml +21 -0
  49. data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_2.xml +21 -0
  50. data/spec/unit/action/destroy_domain_spec.rb +1 -1
  51. data/spec/unit/action/forward_ports_spec.rb +202 -0
  52. data/spec/unit/action/halt_domain_spec.rb +90 -0
  53. data/spec/unit/action/handle_box_image_spec.rb +363 -0
  54. data/spec/unit/action/start_domain_spec.rb +183 -1
  55. data/spec/unit/action/start_domain_spec/clock_timer_rtc.xml +50 -0
  56. data/spec/unit/action/start_domain_spec/default.xml +2 -2
  57. data/spec/unit/action/start_domain_spec/default_added_tpm_path.xml +48 -0
  58. data/spec/unit/action/start_domain_spec/default_added_tpm_version.xml +48 -0
  59. data/spec/unit/action/wait_till_up_spec.rb +22 -21
  60. data/spec/unit/config_spec.rb +395 -127
  61. data/spec/unit/templates/domain_all_settings.xml +14 -3
  62. data/spec/unit/templates/domain_custom_cpu_model.xml +2 -1
  63. data/spec/unit/templates/domain_defaults.xml +2 -1
  64. data/spec/unit/templates/domain_spec.rb +100 -3
  65. data/spec/unit/templates/tpm/version_1.2.xml +54 -0
  66. data/spec/unit/templates/tpm/version_2.0.xml +53 -0
  67. metadata +105 -19
@@ -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,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>
@@ -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