Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 253 lines (211 sloc) 9.571 kb
e0540dfe » frenzykryger
2012-05-16 blueprint lvm-disk-images
1 # vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3 # Copyright 2012 Grid Dynamics
4 # All Rights Reserved.
5 #
6 # Licensed under the Apache License, Version 2.0 (the "License"); you may
7 # not use this file except in compliance with the License. You may obtain
8 # a copy of the License at
9 #
10 # http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15 # License for the specific language governing permissions and limitations
16 # under the License.
17
18 import abc
19 import contextlib
20 import os
21
22 from nova import flags
23 from nova.openstack.common import cfg
24 from nova.openstack.common import excutils
25 from nova import utils
26 from nova.virt.disk import api as disk
27 from nova.virt.libvirt import config
28 from nova.virt.libvirt import utils as libvirt_utils
29
30 __imagebackend_opts = [
31 cfg.StrOpt('libvirt_images_type',
32 default='default',
33 help='VM Images format. Acceptable values are: raw, qcow2, lvm,'
34 ' default. If default is specified,'
35 ' then use_cow_images flag is used instead of this one.'),
36 cfg.StrOpt('libvirt_images_volume_group',
37 default=None,
38 help='LVM Volume Group that is used for VM images, when you'
39 ' specify libvirt_images_type=lvm.'),
40 cfg.BoolOpt('libvirt_sparse_logical_volumes',
41 default=False,
42 help='Create sparse logical volumes (with virtualsize)'
43 ' if this flag is set to True.'),
44 ]
45
46 FLAGS = flags.FLAGS
47 FLAGS.register_opts(__imagebackend_opts)
48
49
50 class Image(object):
51 __metaclass__ = abc.ABCMeta
52
8f166441 » Christoph Thiel
2012-07-24 libvirt driver: set driver name consistently
53 def __init__(self, source_type, driver_format, is_block_dev=False):
e0540dfe » frenzykryger
2012-05-16 blueprint lvm-disk-images
54 """Image initialization.
55
2766ee2b » berrange
2012-07-20 Refactor libvirt imagebackend module to reduce code duplication
56 :source_type: block or file
57 :driver_format: raw or qcow2
8f166441 » Christoph Thiel
2012-07-24 libvirt driver: set driver name consistently
58 :is_block_dev:
e0540dfe » frenzykryger
2012-05-16 blueprint lvm-disk-images
59 """
2766ee2b » berrange
2012-07-20 Refactor libvirt imagebackend module to reduce code duplication
60 self.source_type = source_type
61 self.driver_format = driver_format
8f166441 » Christoph Thiel
2012-07-24 libvirt driver: set driver name consistently
62 self.is_block_dev = is_block_dev
e0540dfe » frenzykryger
2012-05-16 blueprint lvm-disk-images
63
1523fab5 » mikalstill
2012-08-23 External locking for image caching.
64 # NOTE(mikal): We need a lock directory which is shared along with
65 # instance files, to cover the scenario where multiple compute nodes
66 # are trying to create a base file at the same time
67 self.lock_path = os.path.join(FLAGS.instances_path, 'locks')
68
e0540dfe » frenzykryger
2012-05-16 blueprint lvm-disk-images
69 @abc.abstractmethod
70 def create_image(self, prepare_template, base, size, *args, **kwargs):
71 """Create image from template.
72
73 Contains specific behavior for each image type.
74
75 :prepare_template: function, that creates template.
76 Should accept `target` argument.
77 :base: Template name
78 :size: Size of created image in bytes
79 """
80 pass
81
1ec856db » berrange
2012-07-20 Move more libvirt disk setup into the imagebackend module
82 def libvirt_info(self, disk_bus, disk_dev, device_type, cache_mode):
e0540dfe » frenzykryger
2012-05-16 blueprint lvm-disk-images
83 """Get `LibvirtConfigGuestDisk` filled for this image.
84
1ec856db » berrange
2012-07-20 Move more libvirt disk setup into the imagebackend module
85 :disk_dev: Disk bus device name
86 :disk_bus: Disk bus type
e0540dfe » frenzykryger
2012-05-16 blueprint lvm-disk-images
87 :device_type: Device type for this image.
72924739 » berrange
2012-07-20 Move setup of libvirt disk cachemode into imagebackend module
88 :cache_mode: Caching mode for this image
e0540dfe » frenzykryger
2012-05-16 blueprint lvm-disk-images
89 """
2766ee2b » berrange
2012-07-20 Refactor libvirt imagebackend module to reduce code duplication
90 info = config.LibvirtConfigGuestDisk()
91 info.source_type = self.source_type
92 info.source_device = device_type
93 info.target_bus = disk_bus
94 info.target_dev = disk_dev
95 info.driver_cache = cache_mode
96 info.driver_format = self.driver_format
8f166441 » Christoph Thiel
2012-07-24 libvirt driver: set driver name consistently
97 driver_name = libvirt_utils.pick_disk_driver_name(self.is_block_dev)
98 info.driver_name = driver_name
2766ee2b » berrange
2012-07-20 Refactor libvirt imagebackend module to reduce code duplication
99 info.source_path = self.path
100 return info
e0540dfe » frenzykryger
2012-05-16 blueprint lvm-disk-images
101
23987c19 » mikalstill
2012-09-03 Rename imagebackend arguments.
102 def cache(self, fetch_func, filename, size=None, *args, **kwargs):
e0540dfe » frenzykryger
2012-05-16 blueprint lvm-disk-images
103 """Creates image from template.
104
105 Ensures that template and image not already exists.
106 Ensures that base directory exists.
107 Synchronizes on template fetching.
108
23987c19 » mikalstill
2012-09-03 Rename imagebackend arguments.
109 :fetch_func: Function that creates the base image
110 Should accept `target` argument.
111 :filename: Name of the file in the image directory
e0540dfe » frenzykryger
2012-05-16 blueprint lvm-disk-images
112 :size: Size of created image in bytes (optional)
113 """
23987c19 » mikalstill
2012-09-03 Rename imagebackend arguments.
114 @utils.synchronized(filename, external=True, lock_path=self.lock_path)
e0540dfe » frenzykryger
2012-05-16 blueprint lvm-disk-images
115 def call_if_not_exists(target, *args, **kwargs):
116 if not os.path.exists(target):
23987c19 » mikalstill
2012-09-03 Rename imagebackend arguments.
117 fetch_func(target=target, *args, **kwargs)
e0540dfe » frenzykryger
2012-05-16 blueprint lvm-disk-images
118
119 if not os.path.exists(self.path):
120 base_dir = os.path.join(FLAGS.instances_path, '_base')
121 if not os.path.exists(base_dir):
e88218ee » mikalstill
2012-08-26 Move ensure_tree to utils
122 utils.ensure_tree(base_dir)
23987c19 » mikalstill
2012-09-03 Rename imagebackend arguments.
123 base = os.path.join(base_dir, filename)
e0540dfe » frenzykryger
2012-05-16 blueprint lvm-disk-images
124
125 self.create_image(call_if_not_exists, base, size,
23987c19 » mikalstill
2012-09-03 Rename imagebackend arguments.
126 *args, **kwargs)
e0540dfe » frenzykryger
2012-05-16 blueprint lvm-disk-images
127
128
129 class Raw(Image):
6d7bf9a2 » berrange
2012-07-20 Get rid of pointless 'suffix' parameter in libvirt imagebackend
130 def __init__(self, instance, name):
8f166441 » Christoph Thiel
2012-07-24 libvirt driver: set driver name consistently
131 super(Raw, self).__init__("file", "raw", is_block_dev=False)
2766ee2b » berrange
2012-07-20 Refactor libvirt imagebackend module to reduce code duplication
132
e0540dfe » frenzykryger
2012-05-16 blueprint lvm-disk-images
133 self.path = os.path.join(FLAGS.instances_path,
6d7bf9a2 » berrange
2012-07-20 Get rid of pointless 'suffix' parameter in libvirt imagebackend
134 instance, name)
e0540dfe » frenzykryger
2012-05-16 blueprint lvm-disk-images
135
136 def create_image(self, prepare_template, base, size, *args, **kwargs):
1523fab5 » mikalstill
2012-08-23 External locking for image caching.
137 @utils.synchronized(base, external=True, lock_path=self.lock_path)
e0540dfe » frenzykryger
2012-05-16 blueprint lvm-disk-images
138 def copy_raw_image(base, target, size):
139 libvirt_utils.copy_image(base, target)
140 if size:
141 disk.extend(target, size)
142
143 generating = 'image_id' not in kwargs
144 if generating:
145 #Generating image in place
146 prepare_template(target=self.path, *args, **kwargs)
147 else:
148 prepare_template(target=base, *args, **kwargs)
149 with utils.remove_path_on_error(self.path):
150 copy_raw_image(base, self.path, size)
151
152
2766ee2b » berrange
2012-07-20 Refactor libvirt imagebackend module to reduce code duplication
153 class Qcow2(Image):
154 def __init__(self, instance, name):
8f166441 » Christoph Thiel
2012-07-24 libvirt driver: set driver name consistently
155 super(Qcow2, self).__init__("file", "qcow2", is_block_dev=False)
2766ee2b » berrange
2012-07-20 Refactor libvirt imagebackend module to reduce code duplication
156
157 self.path = os.path.join(FLAGS.instances_path,
158 instance, name)
e0540dfe » frenzykryger
2012-05-16 blueprint lvm-disk-images
159
160 def create_image(self, prepare_template, base, size, *args, **kwargs):
1523fab5 » mikalstill
2012-08-23 External locking for image caching.
161 @utils.synchronized(base, external=True, lock_path=self.lock_path)
e0540dfe » frenzykryger
2012-05-16 blueprint lvm-disk-images
162 def copy_qcow2_image(base, target, size):
163 qcow2_base = base
164 if size:
165 size_gb = size / (1024 * 1024 * 1024)
166 qcow2_base += '_%d' % size_gb
167 if not os.path.exists(qcow2_base):
168 with utils.remove_path_on_error(qcow2_base):
169 libvirt_utils.copy_image(base, qcow2_base)
170 disk.extend(qcow2_base, size)
171 libvirt_utils.create_cow_image(qcow2_base, target)
172
173 prepare_template(target=base, *args, **kwargs)
174 with utils.remove_path_on_error(self.path):
175 copy_qcow2_image(base, self.path, size)
176
177
178 class Lvm(Image):
179 @staticmethod
23987c19 » mikalstill
2012-09-03 Rename imagebackend arguments.
180 def escape(filename):
181 return filename.replace('_', '__')
e0540dfe » frenzykryger
2012-05-16 blueprint lvm-disk-images
182
6d7bf9a2 » berrange
2012-07-20 Get rid of pointless 'suffix' parameter in libvirt imagebackend
183 def __init__(self, instance, name):
8f166441 » Christoph Thiel
2012-07-24 libvirt driver: set driver name consistently
184 super(Lvm, self).__init__("block", "raw", is_block_dev=True)
2766ee2b » berrange
2012-07-20 Refactor libvirt imagebackend module to reduce code duplication
185
e0540dfe » frenzykryger
2012-05-16 blueprint lvm-disk-images
186 if not FLAGS.libvirt_images_volume_group:
187 raise RuntimeError(_('You should specify'
188 ' libvirt_images_volume_group'
189 ' flag to use LVM images.'))
190 self.vg = FLAGS.libvirt_images_volume_group
191 self.lv = '%s_%s' % (self.escape(instance),
6d7bf9a2 » berrange
2012-07-20 Get rid of pointless 'suffix' parameter in libvirt imagebackend
192 self.escape(name))
e0540dfe » frenzykryger
2012-05-16 blueprint lvm-disk-images
193 self.path = os.path.join('/dev', self.vg, self.lv)
194 self.sparse = FLAGS.libvirt_sparse_logical_volumes
195
196 def create_image(self, prepare_template, base, size, *args, **kwargs):
1523fab5 » mikalstill
2012-08-23 External locking for image caching.
197 @utils.synchronized(base, external=True, lock_path=self.lock_path)
e0540dfe » frenzykryger
2012-05-16 blueprint lvm-disk-images
198 def create_lvm_image(base, size):
f6f293ea » dprince
2012-07-26 Don't import libvirt_utils in disk api.
199 base_size = disk.get_disk_size(base)
e0540dfe » frenzykryger
2012-05-16 blueprint lvm-disk-images
200 resize = size > base_size
201 size = size if resize else base_size
202 libvirt_utils.create_lvm_image(self.vg, self.lv,
203 size, sparse=self.sparse)
204 cmd = ('dd', 'if=%s' % base, 'of=%s' % self.path, 'bs=4M')
205 utils.execute(*cmd, run_as_root=True)
206 if resize:
207 disk.resize2fs(self.path)
208
209 generated = 'ephemeral_size' in kwargs
210
211 #Generate images with specified size right on volume
212 if generated and size:
213 libvirt_utils.create_lvm_image(self.vg, self.lv,
214 size, sparse=self.sparse)
215 with self.remove_volume_on_error(self.path):
216 prepare_template(target=self.path, *args, **kwargs)
217 else:
218 prepare_template(target=base, *args, **kwargs)
219 with self.remove_volume_on_error(self.path):
220 create_lvm_image(base, size)
221
222 @contextlib.contextmanager
223 def remove_volume_on_error(self, path):
224 try:
225 yield
226 except Exception:
227 with excutils.save_and_reraise_exception():
228 libvirt_utils.remove_logical_volumes(path)
229
230
231 class Backend(object):
232 def __init__(self, use_cow):
233 self.BACKEND = {
234 'raw': Raw,
235 'qcow2': Qcow2,
236 'lvm': Lvm,
237 'default': Qcow2 if use_cow else Raw
238 }
239
23987c19 » mikalstill
2012-09-03 Rename imagebackend arguments.
240 def image(self, instance, name, image_type=None):
e0540dfe » frenzykryger
2012-05-16 blueprint lvm-disk-images
241 """Constructs image for selected backend
242
243 :instance: Instance name.
244 :name: Image name.
245 :image_type: Image type.
246 Optional, is FLAGS.libvirt_images_type by default.
247 """
248 if not image_type:
249 image_type = FLAGS.libvirt_images_type
250 image = self.BACKEND.get(image_type)
251 if not image:
252 raise RuntimeError(_('Unknown image_type=%s') % image_type)
6d7bf9a2 » berrange
2012-07-20 Get rid of pointless 'suffix' parameter in libvirt imagebackend
253 return image(instance, name)
Something went wrong with that request. Please try again.