Skip to content

Commit 438acae

Browse files
authored
Merge pull request #31 from jfontan/qcow2-backing-format
qcow2: get backing storage format from qemu-img
2 parents cfdd435 + bd1f595 commit 438acae

File tree

2 files changed

+186
-45
lines changed

2 files changed

+186
-45
lines changed

lib/cangallo/qcow2.rb

+11-12
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ def self.qemu_img_version
4545
end
4646
end
4747

48+
def self.qemu_img_backing_file_parameter(path)
49+
q = Qcow2.new(path)
50+
format = q.info['format']
51+
"-o backing_file=#{path},backing_fmt=#{format}"
52+
end
53+
4854
def initialize(path=nil)
4955
@path=path
5056
end
@@ -80,15 +86,14 @@ def copy(destination = nil, options = {})
8086
new_path = destination || @path + '.compressed'
8187

8288
command = [:convert, "-p", "-O qcow2"]
83-
#command = ["convert", "-p", "-O qcow2"]
8489
command << '-c' if ops[:compress]
85-
command << "-o backing_file=#{parent}" if parent
90+
command << Qcow2.qemu_img_backing_file_parameter(parent) if parent
8691
command += [@path, new_path]
8792

8893
if ops[:only_copy]
8994
FileUtils.cp(@path, new_path)
9095
else
91-
execute *command
96+
execute(*command)
9297
end
9398

9499
# pp command
@@ -110,7 +115,7 @@ def sparsify(destination)
110115
parent = info['backing_file']
111116
parent_options = ''
112117

113-
parent_options = "-o backing_file=#{parent}" if parent
118+
parent_options = Qcow2.qemu_img_backing_file_parameter(parent) if parent
114119

115120
command = "TMPDIR=#{File.dirname(destination)} virt-sparsify #{parent_options} #{@path} #{destination}"
116121
status, stdout, stderr = systemu command
@@ -152,18 +157,12 @@ def self.execute(command, *params)
152157
end
153158

154159
def self.create_from_base(origin, destination, size=nil)
155-
cmd = [:create, '-f qcow2', "-o backing_file=#{origin}", destination]
156-
cmd << size if size
157-
158-
execute(*cmd)
160+
create(destination, origin, size)
159161
end
160162

161163
def self.create(image, parent=nil, size=nil)
162164
cmd = [:create, '-f qcow2']
163-
if parent
164-
backing_fmt = File.extname(File.basename(parent)).delete_prefix('.')
165-
cmd << "-o backing_file=#{parent},backing_fmt=#{backing_fmt}"
166-
end
165+
cmd << Qcow2.qemu_img_backing_file_parameter(parent) if parent
167166
cmd << image
168167
cmd << size if size
169168
execute(*cmd)

spec/qcow2_spec.rb

+175-33
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
21
# vim:ts=2:sw=2
32

43
#$: << 'lib/cangallo'
54
require 'spec_helper'
65

76
require 'qcow2'
87
require 'fileutils'
8+
require 'systemu'
9+
10+
IMAGE_SIZE = 1 * 1024 * 1024
11+
SHA_1 = '3b71f43ff30f4b15b5cd85dd9e95ebc7e84eb5a3'
12+
SHA_2 = '7d76d48d64d7ac5411d714a4bb83f37e3e5b8df6'
913

1014
describe Cangallo::Qcow2 do
1115
before :all do
@@ -16,70 +20,208 @@
1620
FileUtils.rm_rf(@tmpdir)
1721
end
1822

19-
context "creating the base image" do
23+
context 'creating the base image' do
2024
before :all do
21-
@path = File.join(@tmpdir, 'base.qcow2')
22-
Cangallo::Qcow2.create(@path, nil, 100*1024*1024) # 100 Mb
25+
@qcow2_path = File.join(@tmpdir, 'base.qcow2')
26+
Cangallo::Qcow2.create(@qcow2_path, nil, IMAGE_SIZE) # 100 Mb
27+
28+
q = Cangallo::Qcow2.new(@qcow2_path)
29+
30+
@raw_path = File.join(@tmpdir, 'base.raw')
31+
32+
f = File.open(@raw_path, 'w')
33+
f.seek(IMAGE_SIZE - 1)
34+
f.write("\x00")
35+
f.close
2336
end
2437

25-
it "should be able to create it" do
26-
expect(File).to exist(@path)
38+
it 'should be able to create it' do
39+
expect(File).to exist(@qcow2_path)
40+
expect(File).to exist(@raw_path)
2741
end
2842

29-
it 'should get proper info' do
30-
qcow2 = Cangallo::Qcow2.new(@path)
43+
it 'should get proper info (qcow2)' do
44+
qcow2 = Cangallo::Qcow2.new(@qcow2_path)
3145

3246
info = qcow2.info
3347
expect(info).not_to eq(nil)
3448

35-
expect(info['virtual-size']).to eq(100*1024*1024)
36-
expect(info['cluster-size']).to eq(65536)
49+
expect(info['virtual-size']).to eq(IMAGE_SIZE)
50+
expect(info['cluster-size']).to eq(65_536)
3751
expect(info['format']).to eq('qcow2')
38-
expect(info['actual-size']).to eq(200704)
52+
expect(info['actual-size']).to eq(200_704)
3953
end
4054

41-
if ENV['TRAVIS'] != 'true'
42-
it 'should be able to compute sha1' do
43-
qcow2 = Cangallo::Qcow2.new(@path)
55+
it 'should get proper info (raw)' do
56+
qcow2 = Cangallo::Qcow2.new(@raw_path)
4457

45-
sha1 = qcow2.sha1
46-
expect(sha1).to eq("2c2ceccb5ec5574f791d45b63c940cff20550f9a")
47-
end
58+
info = qcow2.info
59+
expect(info).not_to eq(nil)
60+
61+
expect(info['virtual-size']).to eq(IMAGE_SIZE)
62+
expect(info['cluster-size']).to eq(nil)
63+
expect(info['format']).to eq('raw')
64+
expect(info['actual-size']).to eq(4096)
65+
end
66+
67+
it 'should be able to compute sha1 (qcow2)' do
68+
qcow2 = Cangallo::Qcow2.new(@qcow2_path)
69+
70+
sha1 = qcow2.sha1
71+
expect(sha1).to eq(SHA_1)
72+
end
73+
74+
it 'should be able to compute sha1 (raw)' do
75+
qcow2 = Cangallo::Qcow2.new(@raw_path)
76+
77+
sha1 = qcow2.sha1
78+
expect(sha1).to eq(SHA_1)
4879
end
4980
end
5081

51-
context "with the child image" do
82+
context 'with the child image' do
5283
before :all do
53-
@path = File.join(@tmpdir, 'child.qcow2')
84+
@qcow2_path = File.join(@tmpdir, 'child_qcow2.qcow2')
85+
@raw_path = File.join(@tmpdir, 'child_raw.qcow2')
5486
# 200 Mb
55-
Cangallo::Qcow2.create(@path, File.join(@tmpdir, 'base.qcow2'), 200*1024*1024)
87+
Cangallo::Qcow2.create(@qcow2_path, File.join(@tmpdir, 'base.qcow2'), 2 * IMAGE_SIZE)
88+
Cangallo::Qcow2.create(@raw_path, File.join(@tmpdir, 'base.raw'), 2 * IMAGE_SIZE)
5689
end
5790

58-
it "should be able to create it" do
59-
expect(File).to exist(@path)
91+
it 'should be able to create it' do
92+
expect(File).to exist(@qcow2_path)
93+
expect(File).to exist(@raw_path)
6094
end
6195

62-
it 'should get proper info' do
63-
qcow2 = Cangallo::Qcow2.new(@path)
96+
it 'should get proper info (qcow2)' do
97+
qcow2 = Cangallo::Qcow2.new(@qcow2_path)
6498

6599
info = qcow2.info
66100
expect(info).not_to eq(nil)
67101

68-
expect(info['virtual-size']).to eq(200*1024*1024)
69-
expect(info['cluster-size']).to eq(65536)
102+
expect(info['virtual-size']).to eq(2 * IMAGE_SIZE)
103+
expect(info['cluster-size']).to eq(65_536)
70104
expect(info['format']).to eq('qcow2')
71-
expect(info['actual-size']).to eq(200704)
105+
expect(info['actual-size']).to eq(200_704)
72106
expect(File.basename(info['backing-filename'])).to eq('base.qcow2')
107+
expect(File.basename(info['backing-filename-format'])).to eq('qcow2')
73108
end
74109

75-
if ENV['TRAVIS'] != 'true'
76-
it 'should be able to compute sha1' do
77-
qcow2 = Cangallo::Qcow2.new(@path)
110+
it 'should get proper info (raw)' do
111+
qcow2 = Cangallo::Qcow2.new(@raw_path)
112+
113+
info = qcow2.info
114+
expect(info).not_to eq(nil)
115+
116+
expect(info['virtual-size']).to eq(2 * IMAGE_SIZE)
117+
expect(info['cluster-size']).to eq(65_536)
118+
expect(info['format']).to eq('qcow2')
119+
expect(info['actual-size']).to eq(200_704)
120+
expect(File.basename(info['backing-filename'])).to eq('base.raw')
121+
expect(File.basename(info['backing-filename-format'])).to eq('raw')
122+
end
123+
124+
it 'should be able to compute sha1 (qcow2)' do
125+
qcow2 = Cangallo::Qcow2.new(@qcow2_path)
126+
127+
sha1 = qcow2.sha1
128+
expect(sha1).to eq(SHA_2)
129+
end
130+
131+
it 'should be able to compute sha1 (raw)' do
132+
qcow2 = Cangallo::Qcow2.new(@raw_path)
133+
134+
sha1 = qcow2.sha1
135+
expect(sha1).to eq(SHA_2)
136+
end
137+
end
138+
139+
context 'image actions' do
140+
before :all do
141+
@qcow2_path = File.join(@tmpdir, 'base.qcow2')
142+
@raw_path = File.join(@tmpdir, 'base.raw')
143+
@parent_path = File.join(@tmpdir, 'child_qcow2.qcow2')
144+
end
78145

79-
sha1 = qcow2.sha1
80-
expect(sha1).to eq("fd7c5327c68fcf94b62dc9f58fc1cdb3c8c01258")
146+
it 'should be able to create it' do
147+
expect(File).to exist(@qcow2_path)
148+
expect(File).to exist(@raw_path)
149+
end
150+
151+
it 'should be able to copy it (qcow2)' do
152+
path = File.join(@tmpdir, 'copy_qcow2_copy.qcow2')
153+
q = Cangallo::Qcow2.new(@qcow2_path)
154+
q.copy(path, { parent: @qcow2_path })
155+
156+
expect(File).to exist(path)
157+
158+
info = Cangallo::Qcow2.new(path).info
159+
expect(info).not_to eq(nil)
160+
161+
expect(info['virtual-size']).to eq(IMAGE_SIZE)
162+
expect(info['cluster-size']).to eq(65_536)
163+
expect(info['format']).to eq('qcow2')
164+
expect(info['actual-size']).to eq(266_240)
165+
expect(File.basename(info['backing-filename'])).to eq('base.qcow2')
166+
expect(File.basename(info['backing-filename-format'])).to eq('qcow2')
167+
end
168+
169+
it 'should be able to copy it (raw)' do
170+
path = File.join(@tmpdir, 'copy_raw_copy.qcow2')
171+
q = Cangallo::Qcow2.new(@raw_path)
172+
q.copy(path, { parent: @raw_path })
173+
174+
expect(File).to exist(path)
175+
176+
info = Cangallo::Qcow2.new(path).info
177+
expect(info).not_to eq(nil)
178+
179+
expect(info['virtual-size']).to eq(IMAGE_SIZE)
180+
expect(info['cluster-size']).to eq(65_536)
181+
expect(info['format']).to eq('qcow2')
182+
expect(info['actual-size']).to eq(266_240)
183+
expect(File.basename(info['backing-filename'])).to eq('base.raw')
184+
expect(File.basename(info['backing-filename-format'])).to eq('raw')
185+
end
186+
187+
it 'should be able to sparsify it (qcow2)' do
188+
path = File.join(@tmpdir, 'sparsify.qcow2')
189+
q = Cangallo::Qcow2.new(@parent_path)
190+
q.sparsify(path)
191+
192+
expect(File).to exist(path)
193+
194+
info = Cangallo::Qcow2.new(path).info
195+
expect(info).not_to eq(nil)
196+
197+
expect(info['virtual-size']).to eq(2 * IMAGE_SIZE)
198+
expect(info['cluster-size']).to eq(65_536)
199+
expect(info['format']).to eq('qcow2')
200+
expect(info['actual-size']).to eq(200_704)
201+
expect(info['backing-filename']).to eq(nil)
202+
expect(info['backing-filename-format']).to eq(nil)
203+
end
204+
end
205+
206+
context 'different backing image formats' do
207+
before :all do
208+
formats = ['qcow', 'qcow2', 'qed', 'raw', 'vmdk', 'vdi', 'vhdx']
209+
@images = []
210+
211+
formats.each do |format|
212+
name = File.join(@tmpdir, "base_format.#{format}")
213+
@images << name
214+
cmd = "qemu-img create -f #{format} #{name} #{IMAGE_SIZE}"
215+
pr = systemu cmd
216+
expect(pr[0].success?).to eq(true)
217+
end
218+
end
219+
220+
it 'should be able to create chained images' do
221+
@images.each do |image|
222+
name = "#{image}.chained"
223+
Cangallo::Qcow2.create(name, image, IMAGE_SIZE)
81224
end
82225
end
83226
end
84227
end
85-

0 commit comments

Comments
 (0)