Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 533 lines (412 sloc) 16.771 kB
bb622e6 @sorenh Extend test_virt_driver to also test libvirt driver.
sorenh authored
1 # vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3 # Copyright 2010 United States Government as represented by the
4 # Administrator of the National Aeronautics and Space Administration.
5 # All Rights Reserved.
6 # Copyright (c) 2010 Citrix Systems, Inc.
7 # Copyright (c) 2011 Piston Cloud Computing, Inc
8 # Copyright (c) 2011 OpenStack LLC
9 #
10 # Licensed under the Apache License, Version 2.0 (the "License"); you may
11 # not use this file except in compliance with the License. You may obtain
12 # a copy of the License at
13 #
14 # http://www.apache.org/licenses/LICENSE-2.0
15 #
16 # Unless required by applicable law or agreed to in writing, software
17 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
18 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
19 # License for the specific language governing permissions and limitations
20 # under the License.
21
9bf48de @mikalstill ensure_tree calls mkdir -p
mikalstill authored
22 import errno
0aee886 @mikalstill Move image checksums into a generic file.
mikalstill authored
23 import hashlib
bb622e6 @sorenh Extend test_virt_driver to also test libvirt driver.
sorenh authored
24 import os
0aee886 @mikalstill Move image checksums into a generic file.
mikalstill authored
25 import re
bb622e6 @sorenh Extend test_virt_driver to also test libvirt driver.
sorenh authored
26
27 from nova import exception
28 from nova import flags
0aee886 @mikalstill Move image checksums into a generic file.
mikalstill authored
29 from nova.openstack.common import cfg
3dce38f @zyluo Replace standard json module with openstack.common.jsonutils
zyluo authored
30 from nova.openstack.common import jsonutils
d335457 Switch to common logging.
Andrew Bogott authored
31 from nova.openstack.common import log as logging
9ec0d1b @jogo Alphabetize imports in nova/virt/
jogo authored
32 from nova import utils
bb622e6 @sorenh Extend test_virt_driver to also test libvirt driver.
sorenh authored
33 from nova.virt import images
34
35
0aee886 @mikalstill Move image checksums into a generic file.
mikalstill authored
36 LOG = logging.getLogger(__name__)
37
38
39 util_opts = [
40 cfg.StrOpt('image_info_filename_pattern',
41 default='$instances_path/$base_dir_name/%(image)s.info',
42 help='Allows image information files to be stored in '
43 'non-standard locations')
44 ]
45
46 flags.DECLARE('instances_path', 'nova.compute.manager')
47 flags.DECLARE('base_dir_name', 'nova.compute.manager')
82049af @markmc Refactor away the flags.DEFINE_* helpers
markmc authored
48 FLAGS = flags.FLAGS
0aee886 @mikalstill Move image checksums into a generic file.
mikalstill authored
49 FLAGS.register_opts(util_opts)
bb622e6 @sorenh Extend test_virt_driver to also test libvirt driver.
sorenh authored
50
51
52 def execute(*args, **kwargs):
53 return utils.execute(*args, **kwargs)
54
55
94d8553 @vishvananda Add initiator to initialize_connection
vishvananda authored
56 def get_iscsi_initiator():
57 """Get iscsi initiator name for this machine"""
58 # NOTE(vish) openiscsi stores initiator name in a file that
59 # needs root permission to read.
60 contents = utils.read_file_as_root('/etc/iscsi/initiatorname.iscsi')
61 for l in contents.split('\n'):
62 if l.startswith('InitiatorName='):
63 return l[l.index('=') + 1:].strip()
64
65
bb622e6 @sorenh Extend test_virt_driver to also test libvirt driver.
sorenh authored
66 def create_image(disk_format, path, size):
67 """Create a disk image
68
69 :param disk_format: Disk image format (as known by qemu-img)
70 :param path: Desired location of the disk image
71 :param size: Desired size of disk image. May be given as an int or
72 a string. If given as an int, it will be interpreted
73 as bytes. If it's a string, it should consist of a number
a1c2849 @pixelb various cleanups
pixelb authored
74 with an optional suffix ('K' for Kibibytes,
75 M for Mebibytes, 'G' for Gibibytes, 'T' for Tebibytes).
76 If no suffix is given, it will be interpreted as bytes.
bb622e6 @sorenh Extend test_virt_driver to also test libvirt driver.
sorenh authored
77 """
7dbf9c7 @vishvananda Make snapshots with qemu-img instead of libvirt
vishvananda authored
78 execute('qemu-img', 'create', '-f', disk_format, path, size)
bb622e6 @sorenh Extend test_virt_driver to also test libvirt driver.
sorenh authored
79
80
81 def create_cow_image(backing_file, path):
82 """Create COW image
83
84 Creates a COW image with the given backing file
85
86 :param backing_file: Existing image on which to base the COW image
87 :param path: Desired location of the COW image
88 """
7dbf9c7 @vishvananda Make snapshots with qemu-img instead of libvirt
vishvananda authored
89 execute('qemu-img', 'create', '-f', 'qcow2', '-o',
de5cb27 @jfehlig Use default qemu-img cluster size in libvirt connection driver
jfehlig authored
90 'backing_file=%s' % backing_file, path)
bb622e6 @sorenh Extend test_virt_driver to also test libvirt driver.
sorenh authored
91
92
e0540df @frenzykryger blueprint lvm-disk-images
frenzykryger authored
93 def create_lvm_image(vg, lv, size, sparse=False):
94 """Create LVM image.
95
96 Creates a LVM image with given size.
97
98 :param vg: existing volume group which should hold this image
99 :param lv: name for this image (logical volume)
100 :size: size of image in bytes
101 :sparse: create sparse logical volume
102 """
103 free_space = volume_group_free_space(vg)
104
105 def check_size(size):
106 if size > free_space:
107 raise RuntimeError(_('Insufficient Space on Volume Group %(vg)s.'
108 ' Only %(free_space)db available,'
109 ' but %(size)db required'
110 ' by volume %(lv)s.') % locals())
111
112 if sparse:
113 preallocated_space = 64 * 1024 * 1024
114 check_size(preallocated_space)
115 if free_space < size:
116 LOG.warning(_('Volume group %(vg)s will not be able'
117 ' to hold sparse volume %(lv)s.'
118 ' Virtual volume size is %(size)db,'
119 ' but free space on volume group is'
120 ' only %(free_space)db.') % locals())
121
122 cmd = ('lvcreate', '-L', '%db' % preallocated_space,
123 '--virtualsize', '%db' % size, '-n', lv, vg)
124 else:
125 check_size(size)
126 cmd = ('lvcreate', '-L', '%db' % size, '-n', lv, vg)
127 execute(*cmd, run_as_root=True, attempts=3)
128
129
130 def volume_group_free_space(vg):
131 """Return available space on volume group in bytes.
132
133 :param vg: volume group name
134 """
135 out, err = execute('vgs', '--noheadings', '--nosuffix',
136 '--units', 'b', '-o', 'vg_free', vg,
137 run_as_root=True)
138 return int(out.strip())
139
140
08f172b @frenzykryger Use lvs instead of os.listdir in _cleanup_lvm
frenzykryger authored
141 def list_logical_volumes(vg):
142 """List logical volumes paths for given volume group.
143
144 :param vg: volume group name
145 """
8e11181 @yaguangtang fix deletion of LVM backed instances
yaguangtang authored
146 out, err = execute('lvs', '--noheadings', '-o', 'lv_name', vg,
08f172b @frenzykryger Use lvs instead of os.listdir in _cleanup_lvm
frenzykryger authored
147 run_as_root=True)
148
149 return [line.strip() for line in out.splitlines()]
150
151
a99a802 @pixelb Don't leak info from libvirt LVM backed instances
pixelb authored
152 def logical_volume_size(path):
153 """Get logical volume size in bytes.
154
155 :param path: logical volume path
156 """
157 # TODO(p-draigbrady) POssibly replace with the more general
158 # use of blockdev --getsize64 in future
159 out, _err = execute('lvs', '-o', 'lv_size', '--noheadings', '--units',
160 'b', '--nosuffix', path, run_as_root=True)
161
162 return int(out)
163
164
165 def clear_logical_volume(path):
166 """Obfuscate the logical volume.
167
168 :param path: logical volume path
169 """
170 # TODO(p-draigbrady): We currently overwrite with zeros
171 # but we may want to make this configurable in future
172 # for more or less security conscious setups.
173
174 vol_size = logical_volume_size(path)
175 bs = 1024 * 1024
176 remaining_bytes = vol_size
177
178 # The loop caters for versions of dd that
179 # don't support the iflag=count_bytes option.
180 while remaining_bytes:
181 zero_blocks = remaining_bytes / bs
182 seek_blocks = (vol_size - remaining_bytes) / bs
183 zero_cmd = ('dd', 'bs=%s' % bs,
184 'if=/dev/zero', 'of=%s' % path,
185 'seek=%s' % seek_blocks, 'count=%s' % zero_blocks)
186 if zero_blocks:
187 utils.execute(*zero_cmd, run_as_root=True)
188 remaining_bytes %= bs
189 bs /= 1024 # Limit to 3 iterations
190
191
e0540df @frenzykryger blueprint lvm-disk-images
frenzykryger authored
192 def remove_logical_volumes(*paths):
193 """Remove one or more logical volume."""
a99a802 @pixelb Don't leak info from libvirt LVM backed instances
pixelb authored
194
195 for path in paths:
196 clear_logical_volume(path)
197
e0540df @frenzykryger blueprint lvm-disk-images
frenzykryger authored
198 if paths:
199 lvremove = ('lvremove', '-f') + paths
200 execute(*lvremove, attempts=3, run_as_root=True)
201
202
8f16644 libvirt driver: set driver name consistently
Christoph Thiel authored
203 def pick_disk_driver_name(is_block_dev=False):
204 """Pick the libvirt primary backend driver name
205
206 If the hypervisor supports multiple backend drivers, then the name
207 attribute selects the primary backend driver name, while the optional
208 type attribute provides the sub-type. For example, xen supports a name
209 of "tap", "tap2", "phy", or "file", with a type of "aio" or "qcow2",
210 while qemu only supports a name of "qemu", but multiple types including
211 "raw", "bochs", "qcow2", and "qed".
212
213 :param is_block_dev:
214 :returns: driver_name or None
215 """
216 if FLAGS.libvirt_type == "xen":
217 if is_block_dev:
218 return "phy"
219 else:
220 return "tap"
221 elif FLAGS.libvirt_type in ('kvm', 'qemu'):
222 return "qemu"
223 else:
224 # UML doesn't want a driver_name set
225 return None
226
227
bb622e6 @sorenh Extend test_virt_driver to also test libvirt driver.
sorenh authored
228 def get_disk_size(path):
229 """Get the (virtual) size of a disk image
230
231 :param path: Path to the disk image
232 :returns: Size (in bytes) of the given disk image as it would be seen
233 by a virtual machine.
234 """
5d8e73f @pixelb refactor all uses of the `qemu-img info` command
pixelb authored
235 size = images.qemu_img_info(path)['virtual size']
236 size = size.split('(')[1].split()[0]
237 return int(size)
bb622e6 @sorenh Extend test_virt_driver to also test libvirt driver.
sorenh authored
238
239
240 def get_disk_backing_file(path):
241 """Get the backing file of a disk image
242
243 :param path: Path to the disk image
244 :returns: a path to the image's backing store
245 """
5d8e73f @pixelb refactor all uses of the `qemu-img info` command
pixelb authored
246 backing_file = images.qemu_img_info(path).get('backing file')
247
cb1c1d4 Added resize support for Libvirt/KVM.
Nachi Ueno authored
248 if backing_file:
5d8e73f @pixelb refactor all uses of the `qemu-img info` command
pixelb authored
249 if 'actual path: ' in backing_file:
250 backing_file = backing_file.split('actual path: ')[1][:-1]
0624b7a @pixelb handle updated qemu-img info output
pixelb authored
251 backing_file = os.path.basename(backing_file)
252
bb622e6 @sorenh Extend test_virt_driver to also test libvirt driver.
sorenh authored
253 return backing_file
254
255
3a3ad54 @pixelb improve efficiency of image transfer during migration
pixelb authored
256 def copy_image(src, dest, host=None):
257 """Copy a disk image to an existing directory
bb622e6 @sorenh Extend test_virt_driver to also test libvirt driver.
sorenh authored
258
259 :param src: Source image
260 :param dest: Destination path
3a3ad54 @pixelb improve efficiency of image transfer during migration
pixelb authored
261 :param host: Remote host
bb622e6 @sorenh Extend test_virt_driver to also test libvirt driver.
sorenh authored
262 """
3a3ad54 @pixelb improve efficiency of image transfer during migration
pixelb authored
263
264 if not host:
265 # We shell out to cp because that will intelligently copy
266 # sparse files. I.E. holes will not be written to DEST,
267 # rather recreated efficiently. In addition, since
268 # coreutils 8.11, holes can be read efficiently too.
269 execute('cp', src, dest)
270 else:
271 dest = "%s:%s" % (host, dest)
272 # Try rsync first as that can compress and create sparse dest files.
273 # Note however that rsync currently doesn't read sparse files
274 # efficiently: https://bugzilla.samba.org/show_bug.cgi?id=8918
275 # At least network traffic is mitigated with compression.
276 try:
277 # Do a relatively light weight test first, so that we
278 # can fall back to scp, without having run out of space
279 # on the destination for example.
280 execute('rsync', '--sparse', '--compress', '--dry-run', src, dest)
281 except exception.ProcessExecutionError:
282 execute('scp', src, dest)
283 else:
284 execute('rsync', '--sparse', '--compress', src, dest)
bb622e6 @sorenh Extend test_virt_driver to also test libvirt driver.
sorenh authored
285
286
f4bf828 @justinsb Example config_drive init script, label the config drive
justinsb authored
287 def mkfs(fs, path, label=None):
bb622e6 @sorenh Extend test_virt_driver to also test libvirt driver.
sorenh authored
288 """Format a file or block device
289
290 :param fs: Filesystem type (examples include 'swap', 'ext3', 'ext4'
291 'btrfs', etc.)
292 :param path: Path to file or block device to format
f4bf828 @justinsb Example config_drive init script, label the config drive
justinsb authored
293 :param label: Volume label to use
bb622e6 @sorenh Extend test_virt_driver to also test libvirt driver.
sorenh authored
294 """
295 if fs == 'swap':
296 execute('mkswap', path)
297 else:
f4bf828 @justinsb Example config_drive init script, label the config drive
justinsb authored
298 args = ['mkfs', '-t', fs]
05130da @yaguangtang fix bug lp:1009041,add option "-F" to make mkfs non-interactive.
yaguangtang authored
299 #add -F to force no interactive excute on non-block device.
300 if fs in ['ext3', 'ext4']:
301 args.extend(['-F'])
f4bf828 @justinsb Example config_drive init script, label the config drive
justinsb authored
302 if label:
303 args.extend(['-n', label])
304 args.append(path)
305 execute(*args)
bb622e6 @sorenh Extend test_virt_driver to also test libvirt driver.
sorenh authored
306
307
308 def write_to_file(path, contents, umask=None):
309 """Write the given contents to a file
310
311 :param path: Destination file
312 :param contents: Desired contents of the file
313 :param umask: Umask to set when creating this file (will be reset)
314 """
315 if umask:
316 saved_umask = os.umask(umask)
317
318 try:
319 with open(path, 'w') as f:
320 f.write(contents)
321 finally:
322 if umask:
323 os.umask(saved_umask)
324
325
326 def chown(path, owner):
327 """Change ownership of file or directory
328
329 :param path: File or directory whose ownership to change
330 :param owner: Desired new owner (given as uid or username)
331 """
7dbf9c7 @vishvananda Make snapshots with qemu-img instead of libvirt
vishvananda authored
332 execute('chown', owner, path, run_as_root=True)
333
334
335 def create_snapshot(disk_path, snapshot_name):
336 """Create a snapshot in a disk image
337
338 :param disk_path: Path to disk image
339 :param snapshot_name: Name of snapshot in disk image
340 """
341 qemu_img_cmd = ('qemu-img',
342 'snapshot',
343 '-c',
344 snapshot_name,
345 disk_path)
346 # NOTE(vish): libvirt changes ownership of images
347 execute(*qemu_img_cmd, run_as_root=True)
348
349
350 def delete_snapshot(disk_path, snapshot_name):
351 """Create a snapshot in a disk image
352
353 :param disk_path: Path to disk image
354 :param snapshot_name: Name of snapshot in disk image
355 """
356 qemu_img_cmd = ('qemu-img',
357 'snapshot',
358 '-d',
359 snapshot_name,
360 disk_path)
361 # NOTE(vish): libvirt changes ownership of images
362 execute(*qemu_img_cmd, run_as_root=True)
bb622e6 @sorenh Extend test_virt_driver to also test libvirt driver.
sorenh authored
363
364
365 def extract_snapshot(disk_path, source_fmt, snapshot_name, out_path, dest_fmt):
366 """Extract a named snapshot from a disk image
367
368 :param disk_path: Path to disk image
369 :param snapshot_name: Name of snapshot in disk image
370 :param out_path: Desired path of extracted snapshot
371 """
af06519 @markmc Avoid error during snapshot of ISO booted instance
markmc authored
372 # NOTE(markmc): ISO is just raw to qemu-img
373 if dest_fmt == 'iso':
374 dest_fmt = 'raw'
7dbf9c7 @vishvananda Make snapshots with qemu-img instead of libvirt
vishvananda authored
375 qemu_img_cmd = ('qemu-img',
bb622e6 @sorenh Extend test_virt_driver to also test libvirt driver.
sorenh authored
376 'convert',
377 '-f',
378 source_fmt,
379 '-O',
380 dest_fmt,
381 '-s',
382 snapshot_name,
383 disk_path,
384 out_path)
385 execute(*qemu_img_cmd)
386
387
388 def load_file(path):
389 """Read contents of file
390
391 :param path: File to read
392 """
f01fc5d @pixelb maint: don't require write access when reading files
pixelb authored
393 with open(path, 'r') as fp:
bb622e6 @sorenh Extend test_virt_driver to also test libvirt driver.
sorenh authored
394 return fp.read()
395
396
397 def file_open(*args, **kwargs):
398 """Open file
399
400 see built-in file() documentation for more details
401
402 Note: The reason this is kept in a separate module is to easily
403 be able to provide a stub module that doesn't alter system
404 state at all (for unit tests)
405 """
406 return file(*args, **kwargs)
407
408
409 def file_delete(path):
410 """Delete (unlink) file
411
412 Note: The reason this is kept in a separate module is to easily
413 be able to provide a stub module that doesn't alter system
414 state at all (for unit tests)
415 """
416 return os.unlink(path)
417
418
419 def get_fs_info(path):
420 """Get free/used/total space info for a filesystem
421
422 :param path: Any dirent on the filesystem
423 :returns: A dict containing:
424
425 :free: How much space is free (in bytes)
426 :used: How much space is used (in bytes)
427 :total: How big the filesystem is (in bytes)
428 """
429 hddinfo = os.statvfs(path)
430 total = hddinfo.f_frsize * hddinfo.f_blocks
431 free = hddinfo.f_frsize * hddinfo.f_bavail
432 used = hddinfo.f_frsize * (hddinfo.f_blocks - hddinfo.f_bfree)
433 return {'total': total,
434 'free': free,
435 'used': used}
436
437
d20b48b @pixelb optimize libvirt raw image handling. Bug 924970
pixelb authored
438 def fetch_image(context, target, image_id, user_id, project_id):
439 """Grab image"""
e48c252 @vishvananda Create a flag for force_to_raw for images
vishvananda authored
440 images.fetch_to_raw(context, image_id, target, user_id, project_id)
0aee886 @mikalstill Move image checksums into a generic file.
mikalstill authored
441
442
443 def get_info_filename(base_path):
444 """Construct a filename for storing addtional information about a base
445 image.
446
447 Returns a filename.
448 """
449
450 base_file = os.path.basename(base_path)
451 return (FLAGS.image_info_filename_pattern
452 % {'image': base_file})
453
454
455 def is_valid_info_file(path):
456 """Test if a given path matches the pattern for info files."""
457
458 digest_size = hashlib.sha1().digestsize * 2
459 regexp = (FLAGS.image_info_filename_pattern
460 % {'image': ('([0-9a-f]{%(digest_size)d}|'
461 '[0-9a-f]{%(digest_size)d}_sm|'
462 '[0-9a-f]{%(digest_size)d}_[0-9]+)'
463 % {'digest_size': digest_size})})
464 m = re.match(regexp, path)
465 if m:
466 return True
467 return False
468
469
470 def read_stored_info(base_path, field=None):
471 """Read information about an image.
472
473 Returns an empty dictionary if there is no info, just the field value if
474 a field is requested, or the entire dictionary otherwise.
475 """
476
477 info_file = get_info_filename(base_path)
478 if not os.path.exists(info_file):
2549018 @mikalstill Provide a transition to new .info files.
mikalstill authored
479 # Special case to handle essex checksums being converted
480 old_filename = base_path + '.sha1'
481 if field == 'sha1' and os.path.exists(old_filename):
482 hash_file = open(old_filename)
483 hash_value = hash_file.read()
484 hash_file.close()
485
486 write_stored_info(base_path, field=field, value=hash_value)
487 os.remove(old_filename)
488 d = {field: hash_value}
489
490 else:
491 d = {}
0aee886 @mikalstill Move image checksums into a generic file.
mikalstill authored
492
493 else:
494 LOG.info(_('Reading image info file: %s'), info_file)
495 f = open(info_file, 'r')
496 serialized = f.read().rstrip()
497 f.close()
498 LOG.info(_('Read: %s'), serialized)
499
500 try:
3dce38f @zyluo Replace standard json module with openstack.common.jsonutils
zyluo authored
501 d = jsonutils.loads(serialized)
0aee886 @mikalstill Move image checksums into a generic file.
mikalstill authored
502
503 except ValueError, e:
504 LOG.error(_('Error reading image info file %(filename)s: '
505 '%(error)s'),
506 {'filename': info_file,
507 'error': e})
508 d = {}
509
510 if field:
511 return d.get(field, None)
512 return d
513
514
515 def write_stored_info(target, field=None, value=None):
516 """Write information about an image."""
517
518 if not field:
519 return
520
521 info_file = get_info_filename(target)
e88218e @mikalstill Move ensure_tree to utils
mikalstill authored
522 utils.ensure_tree(os.path.dirname(info_file))
0aee886 @mikalstill Move image checksums into a generic file.
mikalstill authored
523
524 d = read_stored_info(info_file)
525 d[field] = value
3dce38f @zyluo Replace standard json module with openstack.common.jsonutils
zyluo authored
526 serialized = jsonutils.dumps(d)
0aee886 @mikalstill Move image checksums into a generic file.
mikalstill authored
527
528 LOG.info(_('Writing image info file: %s'), info_file)
529 LOG.info(_('Wrote: %s'), serialized)
530 f = open(info_file, 'w')
531 f.write(serialized)
532 f.close()
Something went wrong with that request. Please try again.