kitchen-qemu 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ae36680bcd2808d461d0d57e9be6d0c55a919c43
4
- data.tar.gz: 05b1439ddc31ba48f31b607e2bb96607c428d5ab
3
+ metadata.gz: a4524644c5f8decc92563913b719bed878cb8481
4
+ data.tar.gz: 48e60f381449ce1e9b9b123d7874d24b4d5b67c2
5
5
  SHA512:
6
- metadata.gz: e4013ca5ceba2813668ea367f656baa9bb6d9d7886d885c93ddf4112a32863f3796a43e0d1425735d43406203900e34c9b1b88c1f2d832f01f42b90273dd6b32
7
- data.tar.gz: 029c25cec633dcd7ba9d2a7fc3ca4b5ec9a6a8be80c82691ec43bfb40a1e76fa245a2d93a60ca2e898c5af687d967f342992549dc858563ec81c627d76e9d9c3
6
+ metadata.gz: 82fe2072030831acf5700f87178a8a889485dc949c8254540306dd9e290be1b657fd609688765ef85e548bfde5f1c9fb47a9df7cd26686035dac62639dccc244
7
+ data.tar.gz: 43b5e78b3dfb446405e0f2d809b33db8281fc44636851782c421d82321bbbbef755ea60149d0e4007e14c78ef4ea1c3293d3ddd961891a96622a7163a4251797
@@ -33,13 +33,14 @@ module Kitchen
33
33
  kitchen_driver_api_version 2
34
34
  plugin_version Kitchen::Driver::QEMU_VERSION
35
35
 
36
- default_config :arch, 'x86_64'
37
- default_config :username, 'kitchen'
38
- default_config :password, 'kitchen'
39
- default_config :port, 2222
40
- default_config :display, 'none'
41
- default_config :memory, '512'
42
- default_config :nic_model, 'virtio'
36
+ default_config :arch, 'x86_64'
37
+ default_config :username, 'kitchen'
38
+ default_config :password, 'kitchen'
39
+ default_config :port, 2222
40
+ default_config :display, 'none'
41
+ default_config :memory, '512'
42
+ default_config :nic_model, 'virtio'
43
+ default_config :hostshares, []
43
44
 
44
45
  required_config :image do |_attr, value, _subject|
45
46
  raise UserError, 'Must specify image file' unless value
@@ -60,6 +61,52 @@ module Kitchen
60
61
  config[:binary] = @@ARCHBINARY[config[:arch]] or
61
62
  raise UserError, "Unknown architecture '#{config[:arch]}'"
62
63
  end
64
+
65
+ # kitchen-vagrant compatibility
66
+ config[:hostname] = config[:vm_hostname] if config[:hostname].nil?
67
+
68
+ acpi_poweroff = false
69
+ if config[:image].kind_of?(String)
70
+ config[:image] = [{
71
+ :file => config[:image],
72
+ :readonly => true,
73
+ :snapshot => true,
74
+ }]
75
+ else
76
+ raise UserError, "Invalid image entry for #{instance.to_str}" unless
77
+ config[:image].kind_of?(Array)
78
+ config[:image].each do |image|
79
+ raise UserError, "Invalid image entry for #{instance.to_str}" unless
80
+ image.kind_of?(Hash) && image[:file]
81
+ image[:snapshot] = true if image[:snapshot].nil?
82
+ image[:readonly] = image[:snapshot] if image[:readonly].nil?
83
+ acpi_poweroff = true unless image[:readonly]
84
+ end
85
+ end
86
+ config[:acpi_poweroff] = acpi_poweroff if config[:acpi_poweroff].nil?
87
+
88
+ raise UserError, "Invalid share entry for #{instance.to_str}" unless
89
+ config[:hostshares].kind_of?(Array)
90
+ # kitchen-vagrant compatibility
91
+ if config[:hostshares].empty? && config[:synced_folders].kind_of?(Array)
92
+ config[:synced_folders].each do |folder|
93
+ if !folder[0].kind_of?(String) || !folder[1].kind_of?(String)
94
+ config[:hostshares].clear
95
+ break
96
+ end
97
+ config[:hostshares].push({ :path => folder[0], :mountpoint => folder[1] })
98
+ end
99
+ else
100
+ config[:hostshares].each do |share|
101
+ raise UserError, "Invalid share entry for #{instance.to_str}" unless
102
+ share.kind_of?(Hash) && share[:path]
103
+ raise UserError, "No mountpoint defined for share '#{share[:path]}' of #{instance.to_str}" unless
104
+ share[:mountpoint]
105
+ raise UserError, "Invalid mount options for share '#{share[:path]}' of #{instance.to_str}" unless
106
+ share[:mount_options].nil? || share[:mount_options].kind_of?(Array)
107
+ end
108
+ end
109
+
63
110
  config[:vga] = 'qxl' if config[:spice] && !config[:vga]
64
111
  self
65
112
  end
@@ -69,7 +116,7 @@ module Kitchen
69
116
  # @param state [Hash] mutable instance and driver state
70
117
  # @raise [ActionFailed] if the action could not be completed
71
118
  def create(state)
72
- monitor = monitor_qmp_path
119
+ monitor = monitor_path
73
120
  if File.exist?(monitor)
74
121
  begin
75
122
  mon = UNIXSocket.new(monitor)
@@ -84,28 +131,24 @@ module Kitchen
84
131
 
85
132
  create_privkey or raise ActionFailed, "Unable to create file '#{privkey_path}'"
86
133
 
87
- fqdn = config[:vm_hostname] || instance.name
134
+ fqdn = config[:hostname] || instance.name
88
135
  hostname = fqdn.match(/^([^.]+)/)[0]
89
136
 
90
- state[:hostname] = 'localhost'
91
- state[:port] = config[:port]
92
- state[:username] = config[:username]
93
- state[:password] = config[:password]
137
+ state[:hostname] = 'localhost'
138
+ state[:port] = config[:port]
139
+ state[:username] = config[:username]
140
+ state[:password] = config[:password]
141
+ state[:acpi_poweroff] = config[:acpi_poweroff]
94
142
 
95
143
  cmd = [
96
144
  config[:binary], '-daemonize',
97
145
  '-display', config[:display].to_s,
98
146
  '-chardev', "socket,id=mon-qmp,path=#{monitor},server,nowait",
99
147
  '-mon', 'chardev=mon-qmp,mode=control,default',
100
- '-chardev', "socket,id=mon-rdl,path=#{monitor_readline_path},server,nowait",
101
- '-mon', 'chardev=mon-rdl,mode=readline',
148
+ '-serial', "mon:unix:path=#{serial_path},server,nowait",
102
149
  '-m', config[:memory].to_s,
103
150
  '-net', "nic,model=#{config[:nic_model]}",
104
151
  '-net', "user,net=192.168.1.0/24,hostname=#{hostname},hostfwd=tcp::#{state[:port]}-:22",
105
- '-device', 'virtio-scsi-pci,id=scsi',
106
- '-device', 'scsi-hd,drive=root',
107
- '-drive', "if=none,id=root,readonly,file=#{config[:image]}",
108
- '-snapshot',
109
152
  ]
110
153
 
111
154
  kvm = config[:kvm]
@@ -131,6 +174,25 @@ module Kitchen
131
174
  cmd.push('-spice', config[:spice].to_s) if config[:spice]
132
175
  cmd.push('-vnc', config[:vnc].to_s) if config[:vnc]
133
176
 
177
+ cmd.push('-device', 'virtio-scsi-pci,id=scsi')
178
+ config[:image].each_with_index do |image, i|
179
+ drive = ['if=none', "id=drive#{i}"]
180
+ drive.push('readonly') if image[:readonly]
181
+ drive.push('snapshot=on') if image[:snapshot]
182
+ drive.push("file=#{image[:file]}")
183
+ cmd.push('-device', "scsi-hd,drive=drive#{i}",
184
+ '-drive', drive.join(','))
185
+ end
186
+
187
+ config[:hostshares].each_with_index do |share, i|
188
+ path = share[:path]
189
+ path = "#{config[:kitchen_root]}/#{path}" unless path[0] == '/'
190
+ raise ActionFailed, "Share path '#{path}' not a directory" unless
191
+ ::File.directory?(path)
192
+ cmd.push('-fsdev', "local,id=fsdev#{i},security_model=none,path=#{path}",
193
+ '-device', "virtio-9p-pci,fsdev=fsdev#{i},mount_tag=path#{i}")
194
+ end
195
+
134
196
  info 'Spawning QEMU..'
135
197
  error = nil
136
198
  Open3.popen3({ 'QEMU_AUDIO_DRV' => 'none' }, *cmd) do |_, _, err, thr|
@@ -155,6 +217,11 @@ module Kitchen
155
217
  conn.execute("sudo sh -c 'echo 127.0.0.1 #{names} >> /etc/hosts; hostnamectl set-hostname #{hostname} || hostname #{hostname} || true' 2>/dev/null")
156
218
  conn.execute('install -dm700 "$HOME/.ssh"')
157
219
  conn.execute("echo '#{@@PUBKEY}' > \"$HOME/.ssh/authorized_keys\"")
220
+ config[:hostshares].each_with_index do |share, i|
221
+ options = share[:mount_options] ?
222
+ share[:mount_options].join(',') : 'cache=none,access=any,version=9p2000.L'
223
+ conn.execute("sudo sh -c 'install -dm755 \"#{share[:mountpoint]}\" && mount -t 9p -o trans=virtio,#{options} path#{i} \"#{share[:mountpoint]}\"'")
224
+ end
158
225
  conn.close
159
226
  state[:ssh_key] = privkey_path
160
227
  end
@@ -164,16 +231,22 @@ module Kitchen
164
231
  # @param state [Hash] mutable instance state
165
232
  # @raise [ActionFailed] if the action could not be completed
166
233
  def destroy(state)
167
- monitor = monitor_qmp_path
234
+ monitor = monitor_path
168
235
  return unless File.exist?(monitor)
169
236
 
170
237
  instance.transport.connection(state).close
171
238
 
172
239
  begin
173
240
  mon = QMPClient.new(UNIXSocket.new(monitor), 2)
174
- info 'Quitting QEMU..'
175
- mon.execute('quit')
176
- mon.wait_for_eof(5)
241
+ if state[:acpi_poweroff]
242
+ info 'Sending ACPI poweroff..'
243
+ mon.execute('system_powerdown')
244
+ mon.wait_for_eof(30)
245
+ else
246
+ info 'Quitting QEMU..'
247
+ mon.execute('quit')
248
+ mon.wait_for_eof(5)
249
+ end
177
250
  mon.close
178
251
  rescue Errno::ECONNREFUSED
179
252
  info 'Connection to monitor refused. Assuming QEMU already quit.'
@@ -231,11 +304,11 @@ tY4IM9IaSC2LuPFVc0Kx6TwObdeQScOokIxL3HfayfLKieTLC+w2
231
304
  File.join(config[:kitchen_root], '.kitchen', 'kitchen-qemu.key')
232
305
  end
233
306
 
234
- def monitor_qmp_path
307
+ def monitor_path
235
308
  File.join(config[:kitchen_root], '.kitchen', "#{instance.name}.qmp")
236
309
  end
237
310
 
238
- def monitor_readline_path
311
+ def serial_path
239
312
  File.join(config[:kitchen_root], '.kitchen', "#{instance.name}.mon")
240
313
  end
241
314
 
@@ -247,12 +320,12 @@ tY4IM9IaSC2LuPFVc0Kx6TwObdeQScOokIxL3HfayfLKieTLC+w2
247
320
 
248
321
  def cleanup!
249
322
  begin
250
- File.delete(monitor_qmp_path)
323
+ File.delete(monitor_path)
251
324
  rescue Errno::ENOENT
252
325
  # do nothing
253
326
  end
254
327
  begin
255
- File.delete(monitor_readline_path)
328
+ File.delete(serial_path)
256
329
  rescue Errno::ENOENT
257
330
  # do nothing
258
331
  end
@@ -17,6 +17,6 @@
17
17
  module Kitchen
18
18
  module Driver
19
19
  # Version string for the QEMU Kitchen driver
20
- QEMU_VERSION = '0.1.3'
20
+ QEMU_VERSION = '0.2.0'
21
21
  end
22
22
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kitchen-qemu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Emil Renner Berthing
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-24 00:00:00.000000000 Z
11
+ date: 2016-03-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: test-kitchen