Merge lp:~cerberus/nova/lp809909 into lp:~hudson-openstack/nova/trunk
- lp809909
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 1344 |
Proposed branch: | lp:~cerberus/nova/lp809909 |
Merge into: | lp:~hudson-openstack/nova/trunk |
Diff against target: |
294 lines (+134/-50) 6 files modified
nova/compute/manager.py (+15/-9) nova/tests/test_compute.py (+3/-3) nova/tests/test_xenapi.py (+90/-21) nova/virt/driver.py (+3/-2) nova/virt/xenapi/vmops.py (+18/-12) nova/virt/xenapi_conn.py (+5/-3) |
To merge this branch: | bzr merge lp:~cerberus/nova/lp809909 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jason Kölker (community) | Disapprove | ||
Johannes Erdfelt (community) | Needs Fixing | ||
Review via email: mp+68602@code.launchpad.net |
Commit message
Description of the change
Fixes lp809909
Migrate of instance with no local storage fails with exception
Simply checks to see if the instance has any local storage, and if not, skips over the resize VDI step.
Johannes Erdfelt (johannes.erdfelt) wrote : | # |
Matt Dietz (cerberus) wrote : | # |
To the first point, you can't resize down (currently) so this wouldn't be an issue.
Regarding the second, I think a call to resize online with the same disk size effectively becomes a NOP, but you're right, we shouldn't be calling it at all. So much for taking the easy way out.
Johannes Erdfelt (johannes.erdfelt) wrote : | # |
If it's a NOP, then that's probably not a big deal.
One other concern, which might be moot, would be going from m1.tiny to a larger instance. I originally thought that m1.tiny didn't create a VDI since it wouldn't be necessary with 0GB of local storage, but my logs show it tried to resize a VDI.
Assuming there is no VDI, then we would need to create one first?
The code is a little confusing and I'm not 100% sure what is happening right now.
Matt Dietz (cerberus) wrote : | # |
I just thought of the same case, and TBH, I don't know what it expects to be able to do. I would guess we would have to create a disk in that scenario. When I originally built this feature, I was thinking only in terms of Rackspace style instances, which all have attached disk.
I'll go ahead and file a bug that attempts to reconcile these other cases as necessary.
- 1288. By Matt Dietz
-
CHanges based on feedback
- 1289. By Matt Dietz
-
Renamed the virt driver resize methods to migration for marginally more understandable code
Johannes Erdfelt (johannes.erdfelt) wrote : | # |
You might need to merge with trunk, the preview diff looks like it is showing a conflict.
- 1290. By Matt Dietz
-
Resolved conflict with trunk
Johannes Erdfelt (johannes.erdfelt) wrote : | # |
The code tracks a resize_instance boolean all the way through calling the resize_instance() method, but that method doesn't use the resize_instance boolean at all. Is that intended for future use?
Matt Dietz (cerberus) wrote : | # |
Johannes: it's used in the xenapi virt driver
Passed from compute/manage
43 + self.driver.
44 + resize_instance)
to xenapi_conn
234 + if resize_instance:
235 + self.resize_
- 1291. By Matt Dietz
-
Fixed the virt driver base
- 1292. By Matt Dietz
-
Merge from trunk and conflict resolution
- 1293. By Matt Dietz
-
Removed superfluous parameter
Johannes Erdfelt (johannes.erdfelt) wrote : | # |
After your recent changes, now resize_instance() is called with an extra unexpected parameter.
Jason Kölker (jason-koelker) wrote : | # |
Since cerberus is living it up pimp style at OSCON, I'm going to -steal his karma- shepard the change lp:~jason-koelker/nova/lp809909
Jason Kölker (jason-koelker) wrote : | # |
Please review here: https:/
Preview Diff
1 | === modified file 'nova/compute/manager.py' |
2 | --- nova/compute/manager.py 2011-07-26 19:42:56 +0000 |
3 | +++ nova/compute/manager.py 2011-07-27 18:22:33 +0000 |
4 | @@ -747,7 +747,7 @@ |
5 | local_gb=instance_type['local_gb'], |
6 | instance_type_id=instance_type['id'])) |
7 | |
8 | - self.driver.revert_resize(instance_ref) |
9 | + self.driver.revert_migration(instance_ref) |
10 | self.db.migration_update(context, migration_id, |
11 | {'status': 'reverted'}) |
12 | usage_info = utils.usage_from_instance(instance_ref) |
13 | @@ -845,20 +845,26 @@ |
14 | |
15 | """ |
16 | migration_ref = self.db.migration_get(context, migration_id) |
17 | + |
18 | + resize_instance = False |
19 | instance_ref = self.db.instance_get_by_uuid(context, |
20 | migration_ref.instance_uuid) |
21 | - instance_type = self.db.instance_type_get_by_flavor_id(context, |
22 | - migration_ref['new_flavor_id']) |
23 | - self.db.instance_update(context, instance_ref.uuid, |
24 | - dict(instance_type_id=instance_type['id'], |
25 | - memory_mb=instance_type['memory_mb'], |
26 | - vcpus=instance_type['vcpus'], |
27 | - local_gb=instance_type['local_gb'])) |
28 | + if migration_ref['old_flavor_id'] != migration_ref['new_flavor_id']: |
29 | + instance_type = self.db.instance_type_get_by_flavor_id(context, |
30 | + migration_ref['new_flavor_id']) |
31 | + self.db.instance_update(context, instance_ref.uuid, |
32 | + dict(instance_type_id=instance_type['id'], |
33 | + memory_mb=instance_type['memory_mb'], |
34 | + vcpus=instance_type['vcpus'], |
35 | + local_gb=instance_type['local_gb'])) |
36 | + resize_instance = True |
37 | |
38 | instance_ref = self.db.instance_get_by_uuid(context, |
39 | instance_ref.uuid) |
40 | + |
41 | network_info = self._get_instance_nw_info(context, instance_ref) |
42 | - self.driver.finish_resize(instance_ref, disk_info, network_info) |
43 | + self.driver.finish_migration(instance_ref, disk_info, network_info, |
44 | + resize_instance) |
45 | |
46 | self.db.migration_update(context, migration_id, |
47 | {'status': 'finished', }) |
48 | |
49 | === modified file 'nova/tests/test_compute.py' |
50 | --- nova/tests/test_compute.py 2011-07-22 20:11:39 +0000 |
51 | +++ nova/tests/test_compute.py 2011-07-27 18:22:33 +0000 |
52 | @@ -420,7 +420,7 @@ |
53 | def fake(*args, **kwargs): |
54 | pass |
55 | |
56 | - self.stubs.Set(self.compute.driver, 'finish_resize', fake) |
57 | + self.stubs.Set(self.compute.driver, 'finish_migration', fake) |
58 | self.stubs.Set(self.compute.network_api, 'get_instance_nw_info', fake) |
59 | context = self.context.elevated() |
60 | instance_id = self._create_instance() |
61 | @@ -531,8 +531,8 @@ |
62 | def fake(*args, **kwargs): |
63 | pass |
64 | |
65 | - self.stubs.Set(self.compute.driver, 'finish_resize', fake) |
66 | - self.stubs.Set(self.compute.driver, 'revert_resize', fake) |
67 | + self.stubs.Set(self.compute.driver, 'finish_migration', fake) |
68 | + self.stubs.Set(self.compute.driver, 'revert_migration', fake) |
69 | self.stubs.Set(self.compute.network_api, 'get_instance_nw_info', fake) |
70 | |
71 | self.compute.run_instance(self.context, instance_id) |
72 | |
73 | === modified file 'nova/tests/test_xenapi.py' |
74 | --- nova/tests/test_xenapi.py 2011-07-27 17:07:52 +0000 |
75 | +++ nova/tests/test_xenapi.py 2011-07-27 18:22:33 +0000 |
76 | @@ -783,27 +783,96 @@ |
77 | conn = xenapi_conn.get_connection(False) |
78 | conn.migrate_disk_and_power_off(instance, '127.0.0.1') |
79 | |
80 | - def test_finish_resize(self): |
81 | - instance = db.instance_create(self.context, self.values) |
82 | - stubs.stubout_session(self.stubs, stubs.FakeSessionForMigrationTests) |
83 | - stubs.stubout_loopingcall_start(self.stubs) |
84 | - conn = xenapi_conn.get_connection(False) |
85 | - network_info = [({'bridge': 'fa0', 'id': 0, 'injected': False}, |
86 | - {'broadcast': '192.168.0.255', |
87 | - 'dns': ['192.168.0.1'], |
88 | - 'gateway': '192.168.0.1', |
89 | - 'gateway6': 'dead:beef::1', |
90 | - 'ip6s': [{'enabled': '1', |
91 | - 'ip': 'dead:beef::dcad:beff:feef:0', |
92 | - 'netmask': '64'}], |
93 | - 'ips': [{'enabled': '1', |
94 | - 'ip': '192.168.0.100', |
95 | - 'netmask': '255.255.255.0'}], |
96 | - 'label': 'fake', |
97 | - 'mac': 'DE:AD:BE:EF:00:00', |
98 | - 'rxtx_cap': 3})] |
99 | - conn.finish_resize(instance, dict(base_copy='hurr', cow='durr'), |
100 | - network_info) |
101 | + def test_finish_migrate(self): |
102 | + instance = db.instance_create(self.context, self.values) |
103 | + self.called = False |
104 | + |
105 | + def fake_vdi_resize(*args, **kwargs): |
106 | + self.called = True |
107 | + |
108 | + self.stubs.Set(stubs.FakeSessionForMigrationTests, |
109 | + "VDI_resize_online", fake_vdi_resize) |
110 | + stubs.stubout_session(self.stubs, stubs.FakeSessionForMigrationTests) |
111 | + stubs.stubout_loopingcall_start(self.stubs) |
112 | + conn = xenapi_conn.get_connection(False) |
113 | + network_info = [({'bridge': 'fa0', 'id': 0, 'injected': False}, |
114 | + {'broadcast': '192.168.0.255', |
115 | + 'dns': ['192.168.0.1'], |
116 | + 'gateway': '192.168.0.1', |
117 | + 'gateway6': 'dead:beef::1', |
118 | + 'ip6s': [{'enabled': '1', |
119 | + 'ip': 'dead:beef::dcad:beff:feef:0', |
120 | + 'netmask': '64'}], |
121 | + 'ips': [{'enabled': '1', |
122 | + 'ip': '192.168.0.100', |
123 | + 'netmask': '255.255.255.0'}], |
124 | + 'label': 'fake', |
125 | + 'mac': 'DE:AD:BE:EF:00:00', |
126 | + 'rxtx_cap': 3})] |
127 | + conn.finish_migration(instance, dict(base_copy='hurr', cow='durr'), |
128 | + network_info, resize_instance=True) |
129 | + self.assertEqual(self.called, True) |
130 | + |
131 | + def test_finish_migrate_no_local_storage(self): |
132 | + tiny_type_id = \ |
133 | + instance_types.get_instance_type_by_name('m1.tiny')['id'] |
134 | + self.values.update({'instance_type_id': tiny_type_id, 'local_gb': 0}) |
135 | + instance = db.instance_create(self.context, self.values) |
136 | + |
137 | + def fake_vdi_resize(*args, **kwargs): |
138 | + raise Exception("This shouldn't be called") |
139 | + |
140 | + self.stubs.Set(stubs.FakeSessionForMigrationTests, |
141 | + "VDI_resize_online", fake_vdi_resize) |
142 | + stubs.stubout_session(self.stubs, stubs.FakeSessionForMigrationTests) |
143 | + stubs.stubout_loopingcall_start(self.stubs) |
144 | + conn = xenapi_conn.get_connection(False) |
145 | + network_info = [({'bridge': 'fa0', 'id': 0, 'injected': False}, |
146 | + {'broadcast': '192.168.0.255', |
147 | + 'dns': ['192.168.0.1'], |
148 | + 'gateway': '192.168.0.1', |
149 | + 'gateway6': 'dead:beef::1', |
150 | + 'ip6s': [{'enabled': '1', |
151 | + 'ip': 'dead:beef::dcad:beff:feef:0', |
152 | + 'netmask': '64'}], |
153 | + 'ips': [{'enabled': '1', |
154 | + 'ip': '192.168.0.100', |
155 | + 'netmask': '255.255.255.0'}], |
156 | + 'label': 'fake', |
157 | + 'mac': 'DE:AD:BE:EF:00:00', |
158 | + 'rxtx_cap': 3})] |
159 | + conn.finish_migration(instance, dict(base_copy='hurr', cow='durr'), |
160 | + network_info, resize_instance=True) |
161 | + |
162 | + def test_finish_migrate_no_resize_vdi(self): |
163 | + instance = db.instance_create(self.context, self.values) |
164 | + |
165 | + def fake_vdi_resize(*args, **kwargs): |
166 | + raise Exception("This shouldn't be called") |
167 | + |
168 | + self.stubs.Set(stubs.FakeSessionForMigrationTests, |
169 | + "VDI_resize_online", fake_vdi_resize) |
170 | + stubs.stubout_session(self.stubs, stubs.FakeSessionForMigrationTests) |
171 | + stubs.stubout_loopingcall_start(self.stubs) |
172 | + conn = xenapi_conn.get_connection(False) |
173 | + network_info = [({'bridge': 'fa0', 'id': 0, 'injected': False}, |
174 | + {'broadcast': '192.168.0.255', |
175 | + 'dns': ['192.168.0.1'], |
176 | + 'gateway': '192.168.0.1', |
177 | + 'gateway6': 'dead:beef::1', |
178 | + 'ip6s': [{'enabled': '1', |
179 | + 'ip': 'dead:beef::dcad:beff:feef:0', |
180 | + 'netmask': '64'}], |
181 | + 'ips': [{'enabled': '1', |
182 | + 'ip': '192.168.0.100', |
183 | + 'netmask': '255.255.255.0'}], |
184 | + 'label': 'fake', |
185 | + 'mac': 'DE:AD:BE:EF:00:00', |
186 | + 'rxtx_cap': 3})] |
187 | + |
188 | + # Resize instance would be determined by the compute call |
189 | + conn.finish_migration(instance, dict(base_copy='hurr', cow='durr'), |
190 | + network_info, resize_instance=False) |
191 | |
192 | |
193 | class XenAPIDetermineDiskImageTestCase(test.TestCase): |
194 | |
195 | === modified file 'nova/virt/driver.py' |
196 | --- nova/virt/driver.py 2011-07-22 20:11:39 +0000 |
197 | +++ nova/virt/driver.py 2011-07-27 18:22:33 +0000 |
198 | @@ -122,11 +122,12 @@ |
199 | """Create snapshot from a running VM instance.""" |
200 | raise NotImplementedError() |
201 | |
202 | - def finish_resize(self, instance, disk_info): |
203 | + def finish_migration(self, instance, disk_info, network_info, |
204 | + resize_instance): |
205 | """Completes a resize, turning on the migrated instance""" |
206 | raise NotImplementedError() |
207 | |
208 | - def revert_resize(self, instance): |
209 | + def revert_migration(self, instance): |
210 | """Reverts a resize, powering back on the instance""" |
211 | raise NotImplementedError() |
212 | |
213 | |
214 | === modified file 'nova/virt/xenapi/vmops.py' |
215 | --- nova/virt/xenapi/vmops.py 2011-07-27 17:07:52 +0000 |
216 | +++ nova/virt/xenapi/vmops.py 2011-07-27 18:22:33 +0000 |
217 | @@ -110,17 +110,19 @@ |
218 | instance_infos.append(instance_info) |
219 | return instance_infos |
220 | |
221 | - def revert_resize(self, instance): |
222 | + def revert_migration(self, instance): |
223 | vm_ref = VMHelper.lookup(self._session, instance.name) |
224 | self._start(instance, vm_ref) |
225 | |
226 | - def finish_resize(self, instance, disk_info, network_info): |
227 | + def finish_migration(self, instance, disk_info, network_info, |
228 | + resize_instance): |
229 | vdi_uuid = self.link_disks(instance, disk_info['base_copy'], |
230 | disk_info['cow']) |
231 | vm_ref = self._create_vm(instance, |
232 | [dict(vdi_type='os', vdi_uuid=vdi_uuid)], |
233 | network_info) |
234 | - self.resize_instance(instance, vdi_uuid) |
235 | + if resize_instance: |
236 | + self.resize_instance(instance, vdi_uuid, resize_instance) |
237 | self._spawn(instance, vm_ref) |
238 | |
239 | def _start(self, instance, vm_ref=None): |
240 | @@ -568,18 +570,22 @@ |
241 | return new_cow_uuid |
242 | |
243 | def resize_instance(self, instance, vdi_uuid): |
244 | - """Resize a running instance by changing it's RAM and disk size.""" |
245 | + """Resize a running instance by changing its RAM and disk size.""" |
246 | #TODO(mdietz): this will need to be adjusted for swap later |
247 | #The new disk size must be in bytes |
248 | |
249 | - new_disk_size = str(instance.local_gb * 1024 * 1024 * 1024) |
250 | - instance_name = instance.name |
251 | - instance_local_gb = instance.local_gb |
252 | - LOG.debug(_("Resizing VDI %(vdi_uuid)s for instance %(instance_name)s." |
253 | - " Expanding to %(instance_local_gb)d GB") % locals()) |
254 | - vdi_ref = self._session.call_xenapi('VDI.get_by_uuid', vdi_uuid) |
255 | - self._session.call_xenapi('VDI.resize_online', vdi_ref, new_disk_size) |
256 | - LOG.debug(_("Resize instance %s complete") % (instance.name)) |
257 | + new_disk_size = instance.local_gb * 1024 * 1024 * 1024 |
258 | + if new_disk_size > 0: |
259 | + instance_name = instance.name |
260 | + instance_local_gb = instance.local_gb |
261 | + LOG.debug(_("Resizing VDI %(vdi_uuid)s for instance" |
262 | + "%(instance_name)s. Expanding to %(instance_local_gb)d" |
263 | + " GB") % locals()) |
264 | + vdi_ref = self._session.call_xenapi('VDI.get_by_uuid', vdi_uuid) |
265 | + # for an instance with no local storage |
266 | + self._session.call_xenapi('VDI.resize_online', vdi_ref, |
267 | + str(new_disk_size)) |
268 | + LOG.debug(_("Resize instance %s complete") % (instance.name)) |
269 | |
270 | def reboot(self, instance): |
271 | """Reboot VM instance.""" |
272 | |
273 | === modified file 'nova/virt/xenapi_conn.py' |
274 | --- nova/virt/xenapi_conn.py 2011-07-27 17:07:52 +0000 |
275 | +++ nova/virt/xenapi_conn.py 2011-07-27 18:22:33 +0000 |
276 | @@ -191,13 +191,15 @@ |
277 | """Create VM instance""" |
278 | self._vmops.spawn(instance, network_info) |
279 | |
280 | - def revert_resize(self, instance): |
281 | + def revert_migration(self, instance): |
282 | """Reverts a resize, powering back on the instance""" |
283 | self._vmops.revert_resize(instance) |
284 | |
285 | - def finish_resize(self, instance, disk_info, network_info): |
286 | + def finish_migration(self, instance, disk_info, network_info, |
287 | + resize_instance=False): |
288 | """Completes a resize, turning on the migrated instance""" |
289 | - self._vmops.finish_resize(instance, disk_info, network_info) |
290 | + self._vmops.finish_migration(instance, disk_info, network_info, |
291 | + resize_instance) |
292 | |
293 | def snapshot(self, instance, image_id): |
294 | """ Create snapshot from a running VM instance """ |
Thinking about this more, what would happen if we switched from m1.large (as an example) to m1.tiny? Would the same error occur because 0 is an invalid value? I'd guess we would need to delete the VDI in that case instead of resizing.
Also, in the hypothetical case of two flavors with the same local_gb, a resize of the VDI isn't necessary, right? Should we just skip the call to VDI.resize_online then?