~ubuntu-branches/ubuntu/utopic/heat/utopic-proposed

« back to all changes in this revision

Viewing changes to heat/tests/test_volume.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short
  • Date: 2014-09-08 09:40:59 UTC
  • mfrom: (1.1.16)
  • Revision ID: package-import@ubuntu.com-20140908094059-pzysrm0uy4senjez
Tags: 2014.2~b3-0ubuntu1
New upstream version. 

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
from cinderclient import exceptions as cinder_exp
18
18
from cinderclient.v1 import client as cinderclient
19
19
import mox
 
20
from oslo.config import cfg
20
21
import six
21
22
 
22
23
from heat.common import exception
23
24
from heat.common import template_format
 
25
from heat.db import api as db_api
24
26
from heat.engine.clients.os import cinder
25
27
from heat.engine.clients.os import glance
26
28
from heat.engine.clients.os import nova
27
 
from heat.engine.resources import glance_utils
28
 
from heat.engine.resources import image
29
29
from heat.engine.resources import instance
30
30
from heat.engine.resources import volume as vol
31
31
from heat.engine import rsrc_defn
32
32
from heat.engine import scheduler
33
 
from heat.engine import template
34
33
from heat.tests.common import HeatTestCase
35
34
from heat.tests import utils
36
35
from heat.tests.v1_1 import fakes
60
59
        "Tags" : [{ "Key" : "Usage", "Value" : "Wiki Data Volume" }]
61
60
      }
62
61
    },
63
 
    "DataVolume2" : {
64
 
      "Type" : "AWS::EC2::Volume",
65
 
      "Properties" : {
66
 
        "Size" : "2",
67
 
        "AvailabilityZone" : {"Fn::GetAtt": ["WikiDatabase",
68
 
                                             "AvailabilityZone"]},
69
 
        "Tags" : [{ "Key" : "Usage", "Value" : "Wiki Data Volume2" }]
70
 
      }
71
 
    },
72
62
    "MountPoint" : {
73
63
      "Type" : "AWS::EC2::VolumeAttachment",
74
64
      "Properties" : {
83
73
 
84
74
cinder_volume_template = '''
85
75
heat_template_version: 2013-05-23
86
 
description: This template to define a cinder volume.
 
76
description: Cinder volumes and attachments.
87
77
resources:
88
 
  my_volume:
 
78
  volume:
89
79
    type: OS::Cinder::Volume
90
80
    properties:
 
81
      availability_zone: nova
91
82
      size: 1
92
 
      name: my_vol
93
 
      description: test
 
83
      name: test_name
 
84
      description: test_description
 
85
      metadata:
 
86
        key: value
 
87
  volume2:
 
88
    type: OS::Cinder::Volume
 
89
    properties:
 
90
      availability_zone: nova
 
91
      size: 2
 
92
  attachment:
 
93
    type: OS::Cinder::VolumeAttachment
 
94
    properties:
 
95
      instance_uuid: WikiDatabase
 
96
      volume_id: { get_resource: volume }
 
97
      mountpoint: /dev/vdc
94
98
'''
95
99
 
96
100
 
97
 
class VolumeTest(HeatTestCase):
 
101
class BaseVolumeTest(HeatTestCase):
98
102
    def setUp(self):
99
 
        super(VolumeTest, self).setUp()
 
103
        super(BaseVolumeTest, self).setUp()
100
104
        self.fc = fakes.FakeClient()
101
105
        self.cinder_fc = cinderclient.Client('username', 'password')
102
106
        self.m.StubOutWithMock(cinder.CinderClientPlugin, '_create')
110
114
        self.m.StubOutWithMock(self.fc.volumes, 'create_server_volume')
111
115
        self.m.StubOutWithMock(self.fc.volumes, 'delete_server_volume')
112
116
        self.m.StubOutWithMock(self.fc.volumes, 'get_server_volume')
113
 
 
114
 
    def create_volume(self, t, stack, resource_name):
115
 
        data = t['Resources'][resource_name]
116
 
        data['Properties']['AvailabilityZone'] = 'nova'
117
 
        rsrc = vol.Volume(resource_name,
118
 
                          stack.t.resource_definitions(stack)[resource_name],
119
 
                          stack)
120
 
        self.assertIsNone(rsrc.validate())
121
 
        scheduler.TaskRunner(rsrc.create)()
122
 
        self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
123
 
        return rsrc
124
 
 
125
 
    def create_cinder_volume(self, t, stack, resource_name):
126
 
        rsrc = vol.CinderVolume(resource_name,
127
 
                                stack.t.resource_definitions(
128
 
                                    stack)[resource_name],
129
 
                                stack)
130
 
        self.assertIsNone(rsrc.validate())
131
 
        scheduler.TaskRunner(rsrc.create)()
132
 
        self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
133
 
        return rsrc
134
 
 
135
 
    def create_attachment(self, t, stack, resource_name):
136
 
        resource_defns = stack.t.resource_definitions(stack)
137
 
        rsrc = vol.VolumeAttachment(resource_name,
138
 
                                    resource_defns[resource_name],
139
 
                                    stack)
140
 
        self.assertIsNone(rsrc.validate())
141
 
        scheduler.TaskRunner(rsrc.create)()
142
 
        self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
143
 
        return rsrc
144
 
 
145
 
    def _mock_create_volume(self, fv, stack_name, size=1):
146
 
        cinder.CinderClientPlugin._create().MultipleTimes().AndReturn(
147
 
            self.cinder_fc)
148
 
        vol_name = utils.PhysName(stack_name, 'DataVolume')
149
 
        self.cinder_fc.volumes.create(
150
 
            size=size, availability_zone='nova',
151
 
            display_description=vol_name,
152
 
            display_name=vol_name,
153
 
            metadata={u'Usage': u'Wiki Data Volume'}).AndReturn(fv)
154
 
 
155
 
    def _stubout_delete_volume(self, fv):
 
117
        self.use_cinder = False
 
118
 
 
119
    def _mock_delete_volume(self, fv):
156
120
        self.m.StubOutWithMock(fv, 'delete')
157
121
        fv.delete().AndReturn(True)
158
122
        self.m.StubOutWithMock(fv, 'get')
159
123
        fv.get().AndReturn(None)
160
 
        fv.get().AndRaise(
161
 
            cinder_exp.NotFound('Not found'))
 
124
        fv.get().AndRaise(cinder_exp.NotFound('Not found'))
162
125
        self.m.ReplayAll()
163
126
 
164
127
    def _mock_create_server_volume_script(self, fva,
172
135
            device=device, server_id=server, volume_id=volume).AndReturn(fva)
173
136
        self.cinder_fc.volumes.get(volume).AndReturn(fva)
174
137
 
 
138
    def create_volume(self, t, stack, resource_name):
 
139
        if self.use_cinder:
 
140
            Volume = vol.CinderVolume
 
141
        else:
 
142
            data = t['Resources'][resource_name]
 
143
            data['Properties']['AvailabilityZone'] = 'nova'
 
144
            Volume = vol.Volume
 
145
        rsrc = Volume(resource_name,
 
146
                      stack.t.resource_definitions(stack)[resource_name],
 
147
                      stack)
 
148
        self.assertIsNone(rsrc.validate())
 
149
        scheduler.TaskRunner(rsrc.create)()
 
150
        self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
 
151
        return rsrc
 
152
 
 
153
    def create_attachment(self, t, stack, resource_name):
 
154
        if self.use_cinder:
 
155
            Attachment = vol.CinderVolumeAttachment
 
156
        else:
 
157
            Attachment = vol.VolumeAttachment
 
158
        resource_defns = stack.t.resource_definitions(stack)
 
159
        rsrc = Attachment(resource_name,
 
160
                          resource_defns[resource_name],
 
161
                          stack)
 
162
        self.assertIsNone(rsrc.validate())
 
163
        scheduler.TaskRunner(rsrc.create)()
 
164
        self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
 
165
        return rsrc
 
166
 
 
167
 
 
168
class VolumeTest(BaseVolumeTest):
 
169
 
 
170
    def setUp(self):
 
171
        super(VolumeTest, self).setUp()
 
172
        self.t = template_format.parse(volume_template)
 
173
        self.use_cinder = False
 
174
 
 
175
    def _mock_create_volume(self, fv, stack_name):
 
176
        cinder.CinderClientPlugin._create().MultipleTimes().AndReturn(
 
177
            self.cinder_fc)
 
178
        vol_name = utils.PhysName(stack_name, 'DataVolume')
 
179
        self.cinder_fc.volumes.create(
 
180
            size=1, availability_zone='nova',
 
181
            display_description=vol_name,
 
182
            display_name=vol_name,
 
183
            metadata={u'Usage': u'Wiki Data Volume'}).AndReturn(fv)
 
184
 
175
185
    def test_volume(self):
176
186
        fv = FakeVolume('creating', 'available')
177
187
        stack_name = 'test_volume_stack'
185
195
        self.cinder_fc.volumes.get('vol-123').AndReturn(fv)
186
196
        self.m.ReplayAll()
187
197
 
188
 
        t = template_format.parse(volume_template)
189
 
        stack = utils.parse_stack(t, stack_name=stack_name)
 
198
        stack = utils.parse_stack(self.t, stack_name=stack_name)
190
199
 
191
 
        rsrc = self.create_volume(t, stack, 'DataVolume')
 
200
        rsrc = self.create_volume(self.t, stack, 'DataVolume')
192
201
        self.assertEqual('available', fv.status)
193
202
 
194
203
        fv.status = 'in-use'
195
 
        self.assertRaises(exception.ResourceFailure,
196
 
                          scheduler.TaskRunner(rsrc.destroy))
 
204
        ex = self.assertRaises(exception.ResourceFailure,
 
205
                               scheduler.TaskRunner(rsrc.destroy))
 
206
        self.assertIn("Volume in use", six.text_type(ex))
197
207
 
198
 
        self._stubout_delete_volume(fv)
 
208
        self._mock_delete_volume(fv)
199
209
        fv.status = 'available'
200
210
        scheduler.TaskRunner(rsrc.destroy)()
201
211
 
202
 
        # Test when volume already deleted
203
 
        rsrc.state_set(rsrc.CREATE, rsrc.COMPLETE)
204
 
        scheduler.TaskRunner(rsrc.destroy)()
205
 
 
206
212
        self.m.VerifyAll()
207
213
 
208
214
    def test_volume_default_az(self):
210
216
        stack_name = 'test_volume_stack'
211
217
 
212
218
        # create script
213
 
        nova.NovaClientPlugin._create().MultipleTimes().AndReturn(self.fc)
 
219
        nova.NovaClientPlugin._create().AndReturn(self.fc)
214
220
        self.m.StubOutWithMock(instance.Instance, 'handle_create')
215
221
        self.m.StubOutWithMock(instance.Instance, 'check_create_complete')
216
222
        self.m.StubOutWithMock(vol.VolumeAttachment, 'handle_create')
217
223
        self.m.StubOutWithMock(vol.VolumeAttachment, 'check_create_complete')
218
 
        self.m.StubOutWithMock(image.ImageConstraint, "validate")
 
224
 
219
225
        instance.Instance.handle_create().AndReturn(None)
220
226
        instance.Instance.check_create_complete(None).AndReturn(True)
221
 
        cinder.CinderClientPlugin._create().MultipleTimes().AndReturn(
 
227
        cinder.CinderClientPlugin._create().AndReturn(
222
228
            self.cinder_fc)
223
 
        image.ImageConstraint.validate(
224
 
            mox.IgnoreArg(), mox.IgnoreArg()).MultipleTimes().AndReturn(True)
 
229
        self.stub_ImageConstraint_validate()
225
230
        vol_name = utils.PhysName(stack_name, 'DataVolume')
226
231
        self.cinder_fc.volumes.create(
227
232
            size=1, availability_zone=None,
240
245
        vol.VolumeAttachment.handle_delete().AndReturn(None)
241
246
        self.m.ReplayAll()
242
247
 
243
 
        t = template_format.parse(volume_template)
244
 
        t['Resources'].pop('DataVolume2')
245
 
        stack = utils.parse_stack(t, stack_name=stack_name)
 
248
        stack = utils.parse_stack(self.t, stack_name=stack_name)
246
249
 
247
250
        rsrc = stack['DataVolume']
248
251
        self.assertIsNone(rsrc.validate())
256
259
    def test_volume_create_error(self):
257
260
        fv = FakeVolume('creating', 'error')
258
261
        stack_name = 'test_volume_create_error_stack'
 
262
        cfg.CONF.set_override('action_retry_limit', 0)
259
263
 
260
264
        self._mock_create_volume(fv, stack_name)
261
265
 
262
266
        self.m.ReplayAll()
263
267
 
264
 
        t = template_format.parse(volume_template)
265
 
        t['Resources']['DataVolume']['Properties']['AvailabilityZone'] = 'nova'
266
 
        stack = utils.parse_stack(t, stack_name=stack_name)
267
 
 
268
 
        resource_defns = stack.t.resource_definitions(stack)
269
 
        rsrc = vol.Volume('DataVolume',
270
 
                          resource_defns['DataVolume'],
271
 
                          stack)
272
 
        create = scheduler.TaskRunner(rsrc.create)
273
 
        self.assertRaises(exception.ResourceFailure, create)
 
268
        stack = utils.parse_stack(self.t, stack_name=stack_name)
 
269
        ex = self.assertRaises(exception.ResourceFailure,
 
270
                               self.create_volume, self.t, stack, 'DataVolume')
 
271
        self.assertIn('Went to status error due to "Unknown"',
 
272
                      six.text_type(ex))
274
273
 
275
274
        self.m.VerifyAll()
276
275
 
277
276
    def test_volume_bad_tags(self):
278
 
        t = template_format.parse(volume_template)
279
 
        t['Resources']['DataVolume']['Properties']['Tags'] = [{'Foo': 'bar'}]
280
 
        stack = utils.parse_stack(t, stack_name='test_volume_bad_tags_stack')
 
277
        stack_name = 'test_volume_bad_tags_stack'
 
278
        self.t['Resources']['DataVolume']['Properties'][
 
279
            'Tags'] = [{'Foo': 'bar'}]
 
280
        stack = utils.parse_stack(self.t, stack_name=stack_name)
281
281
 
282
 
        resource_defns = stack.t.resource_definitions(stack)
283
 
        rsrc = vol.Volume('DataVolume',
284
 
                          resource_defns['DataVolume'],
285
 
                          stack)
286
 
        self.assertRaises(exception.StackValidationFailed, rsrc.validate)
 
282
        ex = self.assertRaises(exception.StackValidationFailed,
 
283
                               self.create_volume, self.t, stack, 'DataVolume')
 
284
        self.assertIn('Tags Property error', six.text_type(ex))
287
285
 
288
286
        self.m.VerifyAll()
289
287
 
298
296
 
299
297
        self.m.ReplayAll()
300
298
 
301
 
        t = template_format.parse(volume_template)
302
 
        t['Resources']['DataVolume']['Properties']['AvailabilityZone'] = 'nova'
303
 
        stack = utils.parse_stack(t, stack_name=stack_name)
 
299
        stack = utils.parse_stack(self.t, stack_name=stack_name)
304
300
 
305
 
        scheduler.TaskRunner(stack['DataVolume'].create)()
 
301
        self.create_volume(self.t, stack, 'DataVolume')
306
302
        self.assertEqual('available', fv.status)
307
 
        resource_defns = stack.t.resource_definitions(stack)
308
 
        rsrc = vol.VolumeAttachment('MountPoint',
309
 
                                    resource_defns['MountPoint'],
310
 
                                    stack)
311
 
        create = scheduler.TaskRunner(rsrc.create)
312
 
        self.assertRaises(exception.ResourceFailure, create)
 
303
        ex = self.assertRaises(exception.ResourceFailure,
 
304
                               self.create_attachment,
 
305
                               self.t, stack, 'MountPoint')
 
306
        self.assertIn("Volume attachment failed - Unknown status error",
 
307
                      six.text_type(ex))
313
308
 
314
309
        self.m.VerifyAll()
315
310
 
336
331
 
337
332
        self.m.ReplayAll()
338
333
 
339
 
        t = template_format.parse(volume_template)
340
 
        t['Resources']['DataVolume']['Properties']['AvailabilityZone'] = 'nova'
341
 
        stack = utils.parse_stack(t, stack_name=stack_name)
 
334
        stack = utils.parse_stack(self.t, stack_name=stack_name)
342
335
 
343
 
        scheduler.TaskRunner(stack['DataVolume'].create)()
 
336
        self.create_volume(self.t, stack, 'DataVolume')
344
337
        self.assertEqual('available', fv.status)
345
 
        rsrc = self.create_attachment(t, stack, 'MountPoint')
 
338
        rsrc = self.create_attachment(self.t, stack, 'MountPoint')
346
339
 
347
340
        scheduler.TaskRunner(rsrc.delete)()
348
341
 
373
366
            u'WikiDatabase', 'vol-123').AndRaise(fakes.fake_exception())
374
367
        self.m.ReplayAll()
375
368
 
376
 
        t = template_format.parse(volume_template)
377
 
        t['Resources']['DataVolume']['Properties']['AvailabilityZone'] = 'nova'
378
 
        stack = utils.parse_stack(t, stack_name=stack_name)
 
369
        stack = utils.parse_stack(self.t, stack_name=stack_name)
379
370
 
380
 
        scheduler.TaskRunner(stack['DataVolume'].create)()
 
371
        self.create_volume(self.t, stack, 'DataVolume')
381
372
        self.assertEqual('available', fv.status)
382
 
        rsrc = self.create_attachment(t, stack, 'MountPoint')
 
373
        rsrc = self.create_attachment(self.t, stack, 'MountPoint')
383
374
 
384
375
        scheduler.TaskRunner(rsrc.delete)()
385
376
 
402
393
 
403
394
        self.m.ReplayAll()
404
395
 
405
 
        t = template_format.parse(volume_template)
406
 
        t['Resources']['DataVolume']['Properties']['AvailabilityZone'] = 'nova'
407
 
        stack = utils.parse_stack(t, stack_name=stack_name)
 
396
        stack = utils.parse_stack(self.t, stack_name=stack_name)
408
397
 
409
 
        scheduler.TaskRunner(stack['DataVolume'].create)()
410
 
        rsrc = self.create_attachment(t, stack, 'MountPoint')
 
398
        self.create_volume(self.t, stack, 'DataVolume')
 
399
        rsrc = self.create_attachment(self.t, stack, 'MountPoint')
411
400
 
412
401
        scheduler.TaskRunner(rsrc.delete)()
413
402
 
437
426
 
438
427
        self.m.ReplayAll()
439
428
 
440
 
        t = template_format.parse(volume_template)
441
 
        t['Resources']['DataVolume']['Properties']['AvailabilityZone'] = 'nova'
442
 
        stack = utils.parse_stack(t, stack_name=stack_name)
 
429
        stack = utils.parse_stack(self.t, stack_name=stack_name)
443
430
 
444
 
        scheduler.TaskRunner(stack['DataVolume'].create)()
 
431
        self.create_volume(self.t, stack, 'DataVolume')
445
432
        self.assertEqual('available', fv.status)
446
 
        rsrc = self.create_attachment(t, stack, 'MountPoint')
 
433
        rsrc = self.create_attachment(self.t, stack, 'MountPoint')
447
434
 
448
435
        scheduler.TaskRunner(rsrc.delete)()
449
436
 
467
454
                                             'vol-123').AndReturn(None)
468
455
        self.m.ReplayAll()
469
456
 
470
 
        t = template_format.parse(volume_template)
471
 
        t['Resources']['DataVolume']['Properties']['AvailabilityZone'] = 'nova'
472
 
        stack = utils.parse_stack(t, stack_name=stack_name)
 
457
        stack = utils.parse_stack(self.t, stack_name=stack_name)
473
458
 
474
 
        scheduler.TaskRunner(stack['DataVolume'].create)()
 
459
        self.create_volume(self.t, stack, 'DataVolume')
475
460
        self.assertEqual('available', fv.status)
476
 
        rsrc = self.create_attachment(t, stack, 'MountPoint')
 
461
        rsrc = self.create_attachment(self.t, stack, 'MountPoint')
477
462
        detach_task = scheduler.TaskRunner(rsrc.delete)
478
463
 
479
 
        self.assertRaises(exception.ResourceFailure, detach_task)
 
464
        ex = self.assertRaises(exception.ResourceFailure, detach_task)
 
465
        self.assertIn('Volume detachment failed - Unknown status error',
 
466
                      six.text_type(ex))
480
467
 
481
468
        self.m.VerifyAll()
482
469
 
487
474
        self._mock_create_volume(fv, stack_name)
488
475
        self.m.ReplayAll()
489
476
 
490
 
        t = template_format.parse(volume_template)
491
 
        t['Resources']['DataVolume']['DeletionPolicy'] = 'Delete'
492
 
        stack = utils.parse_stack(t, stack_name=stack_name)
 
477
        self.t['Resources']['DataVolume']['DeletionPolicy'] = 'Delete'
 
478
        stack = utils.parse_stack(self.t, stack_name=stack_name)
493
479
 
494
 
        rsrc = self.create_volume(t, stack, 'DataVolume')
 
480
        rsrc = self.create_volume(self.t, stack, 'DataVolume')
495
481
 
496
482
        self.m.StubOutWithMock(rsrc, "handle_delete")
497
483
        rsrc.handle_delete().AndReturn(None)
502
488
 
503
489
        self.m.VerifyAll()
504
490
 
505
 
    def test_volume_attachment_update_device(self):
506
 
        fv = FakeVolume('creating', 'available')
507
 
        fva = FakeVolume('attaching', 'in-use')
508
 
        fva2 = FakeVolume('attaching', 'in-use')
509
 
        stack_name = 'test_volume_attach_stack'
510
 
 
511
 
        self._mock_create_volume(fv, stack_name)
512
 
 
513
 
        self._mock_create_server_volume_script(fva)
514
 
 
515
 
        # delete script
516
 
        fva = FakeVolume('in-use', 'available')
517
 
        self.fc.volumes.get_server_volume(u'WikiDatabase',
518
 
                                          'vol-123').AndReturn(fva)
519
 
        self.cinder_fc.volumes.get(fva.id).AndReturn(fva)
520
 
        self.fc.volumes.delete_server_volume(
521
 
            'WikiDatabase', 'vol-123').MultipleTimes().AndReturn(None)
522
 
        self.fc.volumes.get_server_volume(u'WikiDatabase',
523
 
                                          'vol-123').AndReturn(fva)
524
 
        self.fc.volumes.get_server_volume(
525
 
            u'WikiDatabase', 'vol-123').AndRaise(fakes.fake_exception())
526
 
 
527
 
        # attach script
528
 
        self._mock_create_server_volume_script(fva2, device=u'/dev/vdd',
529
 
                                               update=True)
530
 
 
531
 
        self.m.ReplayAll()
532
 
 
533
 
        t = template_format.parse(volume_template)
534
 
        t['Resources']['DataVolume']['Properties']['AvailabilityZone'] = 'nova'
535
 
        stack = utils.parse_stack(t, stack_name=stack_name)
536
 
 
537
 
        scheduler.TaskRunner(stack['DataVolume'].create)()
538
 
        self.assertEqual('available', fv.status)
539
 
 
540
 
        rsrc = self.create_attachment(t, stack, 'MountPoint')
541
 
        self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
542
 
 
543
 
        after_t = copy.deepcopy(t)
544
 
        after = after_t['Resources']['MountPoint']
545
 
        after['Properties']['VolumeId'] = 'vol-123'
546
 
        after['Properties']['InstanceId'] = 'WikiDatabase'
547
 
        after['Properties']['Device'] = '/dev/vdd'
548
 
        after_defs = template.Template(after_t).resource_definitions(stack)
549
 
 
550
 
        scheduler.TaskRunner(rsrc.update, after_defs['MountPoint'])()
551
 
 
552
 
        self.assertEqual((rsrc.UPDATE, rsrc.COMPLETE), rsrc.state)
553
 
        self.m.VerifyAll()
554
 
 
555
 
    def test_volume_attachment_update_volume(self):
556
 
        fv = FakeVolume('creating', 'available')
557
 
        fva = FakeVolume('attaching', 'in-use')
558
 
        fv2 = FakeVolume('creating', 'available')
559
 
        fv2.id = 'vol-456'
560
 
        fv2a = FakeVolume('attaching', 'in-use')
561
 
        fv2a.id = 'vol-456'
562
 
        stack_name = 'test_volume_attach_stack'
563
 
 
564
 
        self._mock_create_volume(fv, stack_name)
565
 
 
566
 
        vol2_name = utils.PhysName(stack_name, 'DataVolume2')
567
 
        self.cinder_fc.volumes.create(
568
 
            size=2, availability_zone='nova',
569
 
            display_description=vol2_name,
570
 
            display_name=vol2_name,
571
 
            metadata={u'Usage': u'Wiki Data Volume2'}).AndReturn(fv2)
572
 
 
573
 
        self._mock_create_server_volume_script(fva)
574
 
 
575
 
        # delete script
576
 
        fva = FakeVolume('in-use', 'available')
577
 
        self.fc.volumes.get_server_volume(u'WikiDatabase',
578
 
                                          'vol-123').AndReturn(fva)
579
 
        self.cinder_fc.volumes.get(fva.id).AndReturn(fva)
580
 
        self.fc.volumes.delete_server_volume(
581
 
            'WikiDatabase', 'vol-123').MultipleTimes().AndReturn(None)
582
 
        self.fc.volumes.get_server_volume(u'WikiDatabase',
583
 
                                          'vol-123').AndReturn(fva)
584
 
        self.fc.volumes.get_server_volume(
585
 
            u'WikiDatabase', 'vol-123').AndRaise(fakes.fake_exception())
586
 
 
587
 
        # attach script
588
 
        self._mock_create_server_volume_script(fv2a, volume='vol-456',
589
 
                                               update=True)
590
 
        #self.fc.volumes.create_server_volume(
591
 
            #device=u'/dev/vdc', server_id=u'WikiDatabase',
592
 
            #volume_id='vol-456').AndReturn(fv2a)
593
 
        #self.cinder_fc.volumes.get('vol-456').AndReturn(fv2a)
594
 
 
595
 
        self.m.ReplayAll()
596
 
 
597
 
        t = template_format.parse(volume_template)
598
 
        zone = 'nova'
599
 
        t['Resources']['DataVolume']['Properties']['AvailabilityZone'] = zone
600
 
        t['Resources']['DataVolume2']['Properties']['AvailabilityZone'] = zone
601
 
        stack = utils.parse_stack(t, stack_name=stack_name)
602
 
 
603
 
        scheduler.TaskRunner(stack['DataVolume'].create)()
604
 
        self.assertEqual('available', fv.status)
605
 
        scheduler.TaskRunner(stack['DataVolume2'].create)()
606
 
        self.assertEqual('available', fv2.status)
607
 
 
608
 
        rsrc = self.create_attachment(t, stack, 'MountPoint')
609
 
        self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
610
 
 
611
 
        after_t = copy.deepcopy(t)
612
 
        after = after_t['Resources']['MountPoint']
613
 
        after['Properties']['VolumeId'] = 'vol-456'
614
 
        after['Properties']['InstanceId'] = 'WikiDatabase'
615
 
        after_defs = template.Template(after_t).resource_definitions(stack)
616
 
 
617
 
        scheduler.TaskRunner(rsrc.update, after_defs['MountPoint'])()
618
 
 
619
 
        self.assertEqual((rsrc.UPDATE, rsrc.COMPLETE), rsrc.state)
620
 
        self.assertEqual(fv2a.id, rsrc.resource_id)
621
 
        self.m.VerifyAll()
622
 
 
623
 
    def test_volume_attachment_update_server(self):
624
 
        fv = FakeVolume('creating', 'available')
625
 
        fva = FakeVolume('attaching', 'in-use')
626
 
        fva2 = FakeVolume('attaching', 'in-use')
627
 
        stack_name = 'test_volume_attach_stack'
628
 
 
629
 
        self._mock_create_volume(fv, stack_name)
630
 
 
631
 
        self._mock_create_server_volume_script(fva)
632
 
 
633
 
        # delete script
634
 
        fva = FakeVolume('in-use', 'available')
635
 
        self.fc.volumes.get_server_volume(u'WikiDatabase',
636
 
                                          'vol-123').AndReturn(fva)
637
 
        self.cinder_fc.volumes.get(fva.id).AndReturn(fva)
638
 
        self.fc.volumes.delete_server_volume(
639
 
            'WikiDatabase', 'vol-123').MultipleTimes().AndReturn(None)
640
 
        self.fc.volumes.get_server_volume(u'WikiDatabase',
641
 
                                          'vol-123').AndReturn(fva)
642
 
        self.fc.volumes.get_server_volume(
643
 
            u'WikiDatabase', 'vol-123').AndRaise(fakes.fake_exception())
644
 
 
645
 
        # attach script
646
 
        self._mock_create_server_volume_script(fva2, server=u'WikiDatabase2',
647
 
                                               update=True)
648
 
 
649
 
        self.m.ReplayAll()
650
 
 
651
 
        t = template_format.parse(volume_template)
652
 
        t['Resources']['DataVolume']['Properties']['AvailabilityZone'] = 'nova'
653
 
        stack = utils.parse_stack(t, stack_name=stack_name)
654
 
 
655
 
        scheduler.TaskRunner(stack['DataVolume'].create)()
656
 
        self.assertEqual('available', fv.status)
657
 
 
658
 
        rsrc = self.create_attachment(t, stack, 'MountPoint')
659
 
        self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
660
 
 
661
 
        after_t = copy.deepcopy(t)
662
 
        after = after_t['Resources']['MountPoint']
663
 
        after['Properties']['VolumeId'] = 'vol-123'
664
 
        after['Properties']['InstanceId'] = 'WikiDatabase2'
665
 
        #after['Properties']['Device'] = '/dev/vdd'
666
 
        after_defs = template.Template(after_t).resource_definitions(stack)
667
 
 
668
 
        scheduler.TaskRunner(rsrc.update, after_defs['MountPoint'])()
669
 
 
670
 
        self.assertEqual((rsrc.UPDATE, rsrc.COMPLETE), rsrc.state)
671
 
        self.m.VerifyAll()
 
491
    def test_volume_update_not_supported(self):
 
492
        stack_name = 'test_volume_stack'
 
493
        fv = FakeVolume('creating', 'available')
 
494
 
 
495
        self._mock_create_volume(fv, stack_name)
 
496
        self.m.ReplayAll()
 
497
 
 
498
        t = template_format.parse(volume_template)
 
499
        stack = utils.parse_stack(t, stack_name=stack_name)
 
500
 
 
501
        rsrc = self.create_volume(t, stack, 'DataVolume')
 
502
 
 
503
        props = copy.deepcopy(rsrc.properties.data)
 
504
        props['Size'] = 2
 
505
        props['Tags'] = None
 
506
        props['AvailabilityZone'] = 'other'
 
507
        after = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(), props)
 
508
 
 
509
        updater = scheduler.TaskRunner(rsrc.update, after)
 
510
        ex = self.assertRaises(exception.ResourceFailure, updater)
 
511
        self.assertIn("NotSupported: Update to properties "
 
512
                      "AvailabilityZone, Size, Tags of DataVolume "
 
513
                      "(AWS::EC2::Volume) is not supported",
 
514
                      six.text_type(ex))
 
515
        self.assertEqual((rsrc.UPDATE, rsrc.FAILED), rsrc.state)
672
516
 
673
517
    def test_snapshot(self):
674
518
        stack_name = 'test_volume_stack'
684
528
 
685
529
        self.m.ReplayAll()
686
530
 
687
 
        t = template_format.parse(volume_template)
688
 
        t['Resources']['DataVolume']['DeletionPolicy'] = 'Snapshot'
689
 
        stack = utils.parse_stack(t, stack_name=stack_name)
690
 
 
691
 
        rsrc = self.create_volume(t, stack, 'DataVolume')
692
 
 
693
 
        self._stubout_delete_volume(fv)
 
531
        self.t['Resources']['DataVolume']['DeletionPolicy'] = 'Snapshot'
 
532
        stack = utils.parse_stack(self.t, stack_name=stack_name)
 
533
 
 
534
        rsrc = self.create_volume(self.t, stack, 'DataVolume')
 
535
 
 
536
        self._mock_delete_volume(fv)
694
537
        scheduler.TaskRunner(rsrc.destroy)()
695
538
 
696
539
        self.m.VerifyAll()
708
551
        self.cinder_fc.backups.create('vol-123').AndReturn(fb)
709
552
        self.m.ReplayAll()
710
553
 
711
 
        t = template_format.parse(volume_template)
712
 
        t['Resources']['DataVolume']['DeletionPolicy'] = 'Snapshot'
713
 
        stack = utils.parse_stack(t, stack_name=stack_name)
714
 
 
715
 
        rsrc = self.create_volume(t, stack, 'DataVolume')
716
 
 
717
 
        self.assertRaises(exception.ResourceFailure,
718
 
                          scheduler.TaskRunner(rsrc.destroy))
 
554
        self.t['Resources']['DataVolume']['DeletionPolicy'] = 'Snapshot'
 
555
        stack = utils.parse_stack(self.t, stack_name=stack_name)
 
556
 
 
557
        rsrc = self.create_volume(self.t, stack, 'DataVolume')
 
558
 
 
559
        ex = self.assertRaises(exception.ResourceFailure,
 
560
                               scheduler.TaskRunner(rsrc.destroy))
 
561
        self.assertIn('Unknown status error', six.text_type(ex))
719
562
 
720
563
        self.m.VerifyAll()
721
564
 
722
565
    def test_snapshot_no_volume(self):
723
566
        stack_name = 'test_volume_stack'
 
567
 
 
568
        cfg.CONF.set_override('action_retry_limit', 0)
724
569
        fv = FakeVolume('creating', 'error')
725
570
 
726
571
        self._mock_create_volume(fv, stack_name)
729
574
 
730
575
        self.m.ReplayAll()
731
576
 
732
 
        t = template_format.parse(volume_template)
733
 
        t['Resources']['DataVolume']['DeletionPolicy'] = 'Snapshot'
734
 
        t['Resources']['DataVolume']['Properties']['AvailabilityZone'] = 'nova'
735
 
        stack = utils.parse_stack(t, stack_name=stack_name)
 
577
        self.t['Resources']['DataVolume']['DeletionPolicy'] = 'Snapshot'
 
578
        self.t['Resources']['DataVolume']['Properties'][
 
579
            'AvailabilityZone'] = 'nova'
 
580
        stack = utils.parse_stack(self.t, stack_name=stack_name)
736
581
        resource_defns = stack.t.resource_definitions(stack)
737
582
        rsrc = vol.Volume('DataVolume',
738
583
                          resource_defns['DataVolume'],
739
584
                          stack)
740
585
 
741
586
        create = scheduler.TaskRunner(rsrc.create)
742
 
        self.assertRaises(exception.ResourceFailure, create)
 
587
        ex = self.assertRaises(exception.ResourceFailure, create)
 
588
        self.assertIn('Went to status error due to "Unknown"',
 
589
                      six.text_type(ex))
743
590
 
744
 
        self._stubout_delete_volume(fv)
 
591
        self._mock_delete_volume(fv)
745
592
        scheduler.TaskRunner(rsrc.destroy)()
746
593
 
747
594
        self.m.VerifyAll()
752
599
        fvbr = FakeBackupRestore('vol-123')
753
600
 
754
601
        # create script
755
 
        cinder.CinderClientPlugin._create().MultipleTimes().AndReturn(
 
602
        cinder.CinderClientPlugin._create().AndReturn(
756
603
            self.cinder_fc)
757
604
        self.m.StubOutWithMock(self.cinder_fc.restores, 'restore')
758
605
        self.cinder_fc.restores.restore('backup-123').AndReturn(fvbr)
765
612
 
766
613
        self.m.ReplayAll()
767
614
 
768
 
        t = template_format.parse(volume_template)
769
 
        t['Resources']['DataVolume']['Properties']['SnapshotId'] = 'backup-123'
770
 
        stack = utils.parse_stack(t, stack_name=stack_name)
 
615
        self.t['Resources']['DataVolume']['Properties'][
 
616
            'SnapshotId'] = 'backup-123'
 
617
        stack = utils.parse_stack(self.t, stack_name=stack_name)
771
618
 
772
 
        self.create_volume(t, stack, 'DataVolume')
 
619
        self.create_volume(self.t, stack, 'DataVolume')
773
620
        self.assertEqual('available', fv.status)
774
621
 
775
622
        self.m.VerifyAll()
776
623
 
777
624
    def test_create_from_snapshot_error(self):
778
625
        stack_name = 'test_volume_stack'
 
626
        cfg.CONF.set_override('action_retry_limit', 0)
779
627
        fv = FakeVolumeWithStateTransition('restoring-backup', 'error')
780
628
        fvbr = FakeBackupRestore('vol-123')
781
629
 
782
630
        # create script
783
 
        cinder.CinderClientPlugin._create().MultipleTimes().AndReturn(
 
631
        cinder.CinderClientPlugin._create().AndReturn(
784
632
            self.cinder_fc)
785
633
        self.m.StubOutWithMock(self.cinder_fc.restores, 'restore')
786
634
        self.cinder_fc.restores.restore('backup-123').AndReturn(fvbr)
793
641
 
794
642
        self.m.ReplayAll()
795
643
 
796
 
        t = template_format.parse(volume_template)
797
 
        t['Resources']['DataVolume']['Properties']['SnapshotId'] = 'backup-123'
798
 
        t['Resources']['DataVolume']['Properties']['AvailabilityZone'] = 'nova'
799
 
        stack = utils.parse_stack(t, stack_name=stack_name)
 
644
        self.t['Resources']['DataVolume']['Properties'][
 
645
            'SnapshotId'] = 'backup-123'
 
646
        stack = utils.parse_stack(self.t, stack_name=stack_name)
800
647
 
801
 
        resource_defns = stack.t.resource_definitions(stack)
802
 
        rsrc = vol.Volume('DataVolume',
803
 
                          resource_defns['DataVolume'],
804
 
                          stack)
805
 
        create = scheduler.TaskRunner(rsrc.create)
806
 
        self.assertRaises(exception.ResourceFailure, create)
 
648
        ex = self.assertRaises(exception.ResourceFailure,
 
649
                               self.create_volume, self.t, stack, 'DataVolume')
 
650
        self.assertIn('Went to status error due to "Unknown"',
 
651
                      six.text_type(ex))
807
652
 
808
653
        self.m.VerifyAll()
809
654
 
 
655
    def test_volume_size_constraint(self):
 
656
        self.t['Resources']['DataVolume']['Properties']['Size'] = '0'
 
657
        stack = utils.parse_stack(self.t)
 
658
        error = self.assertRaises(exception.StackValidationFailed,
 
659
                                  self.create_volume,
 
660
                                  self.t, stack, 'DataVolume')
 
661
        self.assertEqual(
 
662
            "Property error : DataVolume: Size 0 is out of "
 
663
            "range (min: 1, max: None)", six.text_type(error))
 
664
 
 
665
 
 
666
class CinderVolumeTest(BaseVolumeTest):
 
667
 
 
668
    def setUp(self):
 
669
        super(CinderVolumeTest, self).setUp()
 
670
        self.t = template_format.parse(cinder_volume_template)
 
671
        self.use_cinder = True
 
672
 
 
673
    def _mock_create_volume(self, fv, stack_name, size=1):
 
674
        cinder.CinderClientPlugin._create().MultipleTimes().AndReturn(
 
675
            self.cinder_fc)
 
676
        self.cinder_fc.volumes.create(
 
677
            size=size, availability_zone='nova',
 
678
            display_description='test_description',
 
679
            display_name='test_name',
 
680
            metadata={'key': 'value'}).AndReturn(fv)
 
681
 
 
682
    def test_cinder_volume_size_constraint(self):
 
683
        self.t['resources']['volume']['properties']['size'] = 0
 
684
        stack = utils.parse_stack(self.t)
 
685
        error = self.assertRaises(exception.StackValidationFailed,
 
686
                                  self.create_volume,
 
687
                                  self.t, stack, 'volume')
 
688
        self.assertEqual(
 
689
            "Property error : volume: size 0 is out of "
 
690
            "range (min: 1, max: None)", six.text_type(error))
 
691
 
810
692
    def test_cinder_create(self):
811
693
        fv = FakeVolume('creating', 'available')
812
694
        stack_name = 'test_volume_stack'
813
695
 
814
 
        cinder.CinderClientPlugin._create().MultipleTimes().AndReturn(
 
696
        cinder.CinderClientPlugin._create().AndReturn(
815
697
            self.cinder_fc)
816
698
        self.cinder_fc.volumes.create(
817
699
            size=1, availability_zone='nova',
818
 
            display_description='CustomDescription',
819
 
            display_name='CustomName',
 
700
            display_description='test_description',
 
701
            display_name='test_name',
820
702
            imageRef='46988116-6703-4623-9dbc-2bc6d284021b',
821
703
            snapshot_id='snap-123',
822
704
            metadata={'key': 'value'},
825
707
 
826
708
        self.m.ReplayAll()
827
709
 
828
 
        t = template_format.parse(volume_template)
829
 
        t['Resources']['DataVolume']['Properties'] = {
830
 
            'size': '1',
831
 
            'availability_zone': 'nova',
832
 
            'name': 'CustomName',
833
 
            'description': 'CustomDescription',
 
710
        self.t['resources']['volume']['properties'].update({
834
711
            'volume_type': 'lvm',
835
 
            'metadata': {'key': 'value'},
836
712
            # Note that specifying all these arguments doesn't work in
837
713
            # practice, as they are conflicting, but we just want to check they
838
714
            # are sent to the backend.
839
715
            'imageRef': '46988116-6703-4623-9dbc-2bc6d284021b',
840
716
            'snapshot_id': 'snap-123',
841
717
            'source_volid': 'vol-012',
842
 
        }
843
 
        stack = utils.parse_stack(t, stack_name=stack_name)
844
 
 
845
 
        resource_defns = stack.t.resource_definitions(stack)
846
 
        rsrc = vol.CinderVolume('DataVolume',
847
 
                                resource_defns['DataVolume'],
848
 
                                stack)
849
 
        self.assertIsNone(rsrc.validate())
850
 
        scheduler.TaskRunner(rsrc.create)()
851
 
        self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
 
718
        })
 
719
        stack = utils.parse_stack(self.t, stack_name=stack_name)
 
720
        self.create_volume(self.t, stack, 'volume')
852
721
        self.assertEqual('available', fv.status)
853
722
 
854
723
        self.m.VerifyAll()
855
724
 
856
 
    def test_volume_size_constraint_os(self):
857
 
        t = template_format.parse(volume_template)
858
 
        t['Resources']['DataVolume']['Properties'] = {'size': '0'}
859
 
        stack = utils.parse_stack(t)
860
 
        resource_defns = stack.t.resource_definitions(stack)
861
 
        rsrc = vol.CinderVolume(
862
 
            'DataVolume', resource_defns['DataVolume'], stack)
863
 
        error = self.assertRaises(exception.StackValidationFailed,
864
 
                                  rsrc.validate)
865
 
        self.assertEqual(
866
 
            "Property error : DataVolume: size 0 is out of "
867
 
            "range (min: 1, max: None)", str(error))
868
 
 
869
 
    def test_volume_size_constraint_aws(self):
870
 
        t = template_format.parse(volume_template)
871
 
        t['Resources']['DataVolume']['Properties']['Size'] = '0'
872
 
        stack = utils.parse_stack(t)
873
 
        resource_defns = stack.t.resource_definitions(stack)
874
 
        rsrc = vol.Volume(
875
 
            'DataVolume', resource_defns['DataVolume'], stack)
876
 
        error = self.assertRaises(exception.StackValidationFailed,
877
 
                                  rsrc.validate)
878
 
        self.assertEqual(
879
 
            "Property error : DataVolume: Size 0 is out of "
880
 
            "range (min: 1, max: None)", str(error))
881
 
 
882
725
    def test_cinder_create_from_image(self):
883
726
        fv = FakeVolumeWithStateTransition('downloading', 'available')
884
727
        stack_name = 'test_volume_stack'
885
728
        image_id = '46988116-6703-4623-9dbc-2bc6d284021b'
886
 
        cinder.CinderClientPlugin._create().MultipleTimes().AndReturn(
 
729
        cinder.CinderClientPlugin._create().AndReturn(
887
730
            self.cinder_fc)
888
 
        g_cli_mock = self.m.CreateMockAnything()
889
 
        self.m.StubOutWithMock(glance.GlanceClientPlugin, '_create')
890
 
        glance.GlanceClientPlugin._create().MultipleTimes().AndReturn(
891
 
            g_cli_mock)
892
 
        self.m.StubOutWithMock(glance_utils, 'get_image_id')
893
 
        glance_utils.get_image_id(g_cli_mock, image_id).MultipleTimes().\
894
 
            AndReturn(image_id)
 
731
        self.m.StubOutWithMock(glance.GlanceClientPlugin, 'get_image_id')
 
732
        glance.GlanceClientPlugin.get_image_id(
 
733
            image_id).MultipleTimes().AndReturn(image_id)
895
734
 
896
735
        self.cinder_fc.volumes.create(
897
736
            size=1, availability_zone='nova',
901
740
 
902
741
        self.m.ReplayAll()
903
742
 
904
 
        t = template_format.parse(volume_template)
905
 
        t['Resources']['DataVolume']['Properties'] = {
 
743
        self.t['resources']['volume']['properties'] = {
906
744
            'size': '1',
907
745
            'name': 'ImageVolume',
908
746
            'description': 'ImageVolumeDescription',
909
747
            'availability_zone': 'nova',
910
748
            'image': image_id,
911
749
        }
912
 
        stack = utils.parse_stack(t, stack_name=stack_name)
913
 
 
914
 
        resource_defns = stack.t.resource_definitions(stack)
915
 
        rsrc = vol.CinderVolume('DataVolume',
916
 
                                resource_defns['DataVolume'],
917
 
                                stack)
918
 
        self.assertIsNone(rsrc.validate())
919
 
        scheduler.TaskRunner(rsrc.create)()
920
 
        self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
 
750
        stack = utils.parse_stack(self.t, stack_name=stack_name)
 
751
        self.create_volume(self.t, stack, 'volume')
921
752
        self.assertEqual('available', fv.status)
922
753
 
923
754
        self.m.VerifyAll()
926
757
        fv = FakeVolume('creating', 'available')
927
758
        stack_name = 'test_volume_stack'
928
759
 
929
 
        cinder.CinderClientPlugin._create().MultipleTimes().AndReturn(
 
760
        cinder.CinderClientPlugin._create().AndReturn(
930
761
            self.cinder_fc)
931
 
        vol_name = utils.PhysName(stack_name, 'DataVolume')
 
762
        vol_name = utils.PhysName(stack_name, 'volume')
932
763
        self.cinder_fc.volumes.create(
933
764
            size=1, availability_zone='nova',
934
765
            display_description=None,
936
767
 
937
768
        self.m.ReplayAll()
938
769
 
939
 
        t = template_format.parse(volume_template)
940
 
        t['Resources']['DataVolume']['Properties'] = {
 
770
        self.t['resources']['volume']['properties'] = {
941
771
            'size': '1',
942
772
            'availability_zone': 'nova',
943
773
        }
944
 
        stack = utils.parse_stack(t, stack_name=stack_name)
945
 
 
946
 
        resource_defns = stack.t.resource_definitions(stack)
947
 
        rsrc = vol.CinderVolume('DataVolume',
948
 
                                resource_defns['DataVolume'],
949
 
                                stack)
950
 
        self.assertIsNone(rsrc.validate())
951
 
        scheduler.TaskRunner(rsrc.create)()
952
 
        self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
 
774
        stack = utils.parse_stack(self.t, stack_name=stack_name)
 
775
        self.create_volume(self.t, stack, 'volume')
953
776
        self.assertEqual('available', fv.status)
954
777
 
955
778
        self.m.VerifyAll()
963
786
                        created_at='2013-02-25T02:40:21.000000')
964
787
        stack_name = 'test_volume_stack'
965
788
 
966
 
        cinder.CinderClientPlugin._create().MultipleTimes().AndReturn(
967
 
            self.cinder_fc)
968
 
        vol_name = utils.PhysName(stack_name, 'DataVolume')
969
 
        self.cinder_fc.volumes.create(
970
 
            size=1, availability_zone='nova',
971
 
            display_description=None,
972
 
            display_name=vol_name).AndReturn(fv)
973
 
 
 
789
        self._mock_create_volume(fv, stack_name)
974
790
        self.cinder_fc.volumes.get('vol-123').MultipleTimes().AndReturn(fv)
975
791
 
976
792
        self.m.ReplayAll()
977
793
 
978
 
        t = template_format.parse(volume_template)
979
 
        t['Resources']['DataVolume']['Properties'] = {
980
 
            'size': '1',
981
 
            'availability_zone': 'nova',
982
 
        }
983
 
        stack = utils.parse_stack(t, stack_name=stack_name)
 
794
        stack = utils.parse_stack(self.t, stack_name=stack_name)
 
795
        rsrc = self.create_volume(self.t, stack, 'volume')
984
796
 
985
 
        resource_defns = stack.t.resource_definitions(stack)
986
 
        rsrc = vol.CinderVolume('DataVolume',
987
 
                                resource_defns['DataVolume'],
988
 
                                stack)
989
 
        scheduler.TaskRunner(rsrc.create)()
990
797
        self.assertEqual(u'zone1', rsrc.FnGetAtt('availability_zone'))
991
798
        self.assertEqual(u'1', rsrc.FnGetAtt('size'))
992
799
        self.assertEqual(u'snap-123', rsrc.FnGetAtt('snapshot_id'))
995
802
        self.assertEqual(u'lvm', rsrc.FnGetAtt('volume_type'))
996
803
        self.assertEqual(json.dumps({'key': 'value'}),
997
804
                         rsrc.FnGetAtt('metadata'))
 
805
        self.assertEqual({'key': 'value'},
 
806
                         rsrc.FnGetAtt('metadata_values'))
998
807
        self.assertEqual(u'None', rsrc.FnGetAtt('source_volid'))
999
808
        self.assertEqual(u'available', rsrc.FnGetAtt('status'))
1000
809
        self.assertEqual(u'2013-02-25T02:40:21.000000',
1003
812
        error = self.assertRaises(exception.InvalidTemplateAttribute,
1004
813
                                  rsrc.FnGetAtt, 'unknown')
1005
814
        self.assertEqual(
1006
 
            'The Referenced Attribute (DataVolume unknown) is incorrect.',
1007
 
            str(error))
 
815
            'The Referenced Attribute (volume unknown) is incorrect.',
 
816
            six.text_type(error))
1008
817
 
1009
818
        self.m.VerifyAll()
1010
819
 
1031
840
 
1032
841
        self.m.ReplayAll()
1033
842
 
1034
 
        t = template_format.parse(volume_template)
1035
 
        t['Resources']['DataVolume']['Properties']['AvailabilityZone'] = 'nova'
1036
 
        t['Resources']['MountPoint']['Properties'] = {
1037
 
            'instance_uuid': {'Ref': 'WikiDatabase'},
1038
 
            'volume_id': {'Ref': 'DataVolume'},
1039
 
            'mountpoint': '/dev/vdc'
1040
 
        }
1041
 
        stack = utils.parse_stack(t, stack_name=stack_name)
 
843
        stack = utils.parse_stack(self.t, stack_name=stack_name)
1042
844
 
1043
 
        scheduler.TaskRunner(stack['DataVolume'].create)()
 
845
        self.create_volume(self.t, stack, 'volume')
1044
846
        self.assertEqual('available', fv.status)
1045
 
        resource_defns = stack.t.resource_definitions(stack)
1046
 
        rsrc = vol.CinderVolumeAttachment('MountPoint',
1047
 
                                          resource_defns['MountPoint'],
1048
 
                                          stack)
1049
 
        self.assertIsNone(rsrc.validate())
1050
 
        scheduler.TaskRunner(rsrc.create)()
1051
 
        self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
1052
 
 
 
847
        rsrc = self.create_attachment(self.t, stack, 'attachment')
1053
848
        scheduler.TaskRunner(rsrc.delete)()
1054
849
 
1055
850
        self.m.VerifyAll()
1056
851
 
1057
 
    def test_volume_shrink_fails(self):
 
852
    def test_cinder_volume_shrink_fails(self):
1058
853
        fv = FakeVolume('creating', 'available', size=2)
1059
854
        stack_name = 'test_volume_stack'
1060
855
 
1065
860
 
1066
861
        self.m.ReplayAll()
1067
862
 
1068
 
        t = template_format.parse(volume_template)
1069
 
        t['Resources']['DataVolume']['Properties']['Size'] = 2
1070
 
        stack = utils.parse_stack(t, stack_name=stack_name)
 
863
        self.t['resources']['volume']['properties']['size'] = 2
 
864
        stack = utils.parse_stack(self.t, stack_name=stack_name)
1071
865
 
1072
 
        rsrc = self.create_volume(t, stack, 'DataVolume')
 
866
        rsrc = self.create_volume(self.t, stack, 'volume')
1073
867
        self.assertEqual('available', fv.status)
1074
868
 
1075
869
        props = copy.deepcopy(rsrc.properties.data)
1076
 
        props['Size'] = 1
 
870
        props['size'] = 1
1077
871
        after = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(), props)
1078
872
 
1079
873
        update_task = scheduler.TaskRunner(rsrc.update, after)
1084
878
        self.assertEqual((rsrc.UPDATE, rsrc.FAILED), rsrc.state)
1085
879
        self.m.VerifyAll()
1086
880
 
1087
 
    def test_volume_extend_detached(self):
 
881
    def test_cinder_volume_extend_detached(self):
1088
882
        fv = FakeVolume('creating', 'available', size=1, attachments=[])
1089
883
        stack_name = 'test_volume_stack'
1090
884
 
1100
894
 
1101
895
        self.m.ReplayAll()
1102
896
 
1103
 
        t = template_format.parse(volume_template)
1104
 
        stack = utils.parse_stack(t, stack_name=stack_name)
 
897
        stack = utils.parse_stack(self.t, stack_name=stack_name)
1105
898
 
1106
 
        rsrc = self.create_volume(t, stack, 'DataVolume')
 
899
        rsrc = self.create_volume(self.t, stack, 'volume')
1107
900
        self.assertEqual('available', fv.status)
1108
901
 
1109
902
        props = copy.deepcopy(rsrc.properties.data)
1110
 
        props['Size'] = 2
 
903
        props['size'] = 2
1111
904
        after = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(), props)
1112
905
 
1113
906
        update_task = scheduler.TaskRunner(rsrc.update, after)
1116
909
        self.assertEqual((rsrc.UPDATE, rsrc.COMPLETE), rsrc.state)
1117
910
        self.m.VerifyAll()
1118
911
 
1119
 
    def test_volume_extend_fails_to_start(self):
 
912
    def test_cinder_volume_extend_fails_to_start(self):
1120
913
        fv = FakeVolume('creating', 'available', size=1, attachments=[])
1121
914
        stack_name = 'test_volume_stack'
1122
915
 
1128
921
        self.cinder_fc.volumes.get(fv.id).AndReturn(fv2)
1129
922
 
1130
923
        self.cinder_fc.volumes.extend(fv.id, 2).AndRaise(
1131
 
            cinder_exp.OverLimit)
 
924
            cinder_exp.OverLimit(413))
1132
925
 
1133
926
        self.m.ReplayAll()
1134
927
 
1135
 
        t = template_format.parse(volume_template)
1136
 
        stack = utils.parse_stack(t, stack_name=stack_name)
 
928
        stack = utils.parse_stack(self.t, stack_name=stack_name)
1137
929
 
1138
 
        rsrc = self.create_volume(t, stack, 'DataVolume')
 
930
        rsrc = self.create_volume(self.t, stack, 'volume')
1139
931
        self.assertEqual('available', fv.status)
1140
932
 
1141
933
        props = copy.deepcopy(rsrc.properties.data)
1142
 
        props['Size'] = 2
 
934
        props['size'] = 2
1143
935
        after = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(), props)
1144
936
 
1145
937
        update_task = scheduler.TaskRunner(rsrc.update, after)
1146
 
        self.assertRaises(exception.ResourceFailure, update_task)
 
938
        ex = self.assertRaises(exception.ResourceFailure, update_task)
 
939
        self.assertIn('Over limit', six.text_type(ex))
1147
940
 
1148
941
        self.assertEqual((rsrc.UPDATE, rsrc.FAILED), rsrc.state)
1149
942
        self.m.VerifyAll()
1150
943
 
1151
 
    def test_volume_extend_fails_to_complete(self):
 
944
    def test_cinder_volume_extend_fails_to_complete(self):
1152
945
        fv = FakeVolume('creating', 'available', size=1, attachments=[])
1153
946
        stack_name = 'test_volume_stack'
1154
947
 
1164
957
 
1165
958
        self.m.ReplayAll()
1166
959
 
1167
 
        t = template_format.parse(volume_template)
1168
 
        stack = utils.parse_stack(t, stack_name=stack_name)
 
960
        stack = utils.parse_stack(self.t, stack_name=stack_name)
1169
961
 
1170
 
        rsrc = self.create_volume(t, stack, 'DataVolume')
 
962
        rsrc = self.create_volume(self.t, stack, 'volume')
1171
963
        self.assertEqual('available', fv.status)
1172
964
 
1173
965
        props = copy.deepcopy(rsrc.properties.data)
1174
 
        props['Size'] = 2
 
966
        props['size'] = 2
1175
967
        after = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(), props)
1176
968
 
1177
969
        update_task = scheduler.TaskRunner(rsrc.update, after)
1178
970
        ex = self.assertRaises(exception.ResourceFailure, update_task)
1179
 
        self.assertEqual("Error: Resize failed: Volume vol-123 is in "
1180
 
                         "error_extending state.", six.text_type(ex))
 
971
        self.assertIn("Volume resize failed - Unknown status error_extending",
 
972
                      six.text_type(ex))
1181
973
 
1182
974
        self.assertEqual((rsrc.UPDATE, rsrc.FAILED), rsrc.state)
1183
975
        self.m.VerifyAll()
1184
976
 
1185
 
    def test_volume_extend_attached(self):
 
977
    def test_cinder_volume_extend_attached(self):
1186
978
        # create script
1187
979
        fv = FakeVolume('creating', 'available')
1188
980
        stack_name = 'test_volume_stack'
1223
1015
 
1224
1016
        self.m.ReplayAll()
1225
1017
 
1226
 
        t = template_format.parse(volume_template)
1227
 
        stack = utils.parse_stack(t, stack_name=stack_name)
 
1018
        stack = utils.parse_stack(self.t, stack_name=stack_name)
1228
1019
 
1229
 
        rsrc = self.create_volume(t, stack, 'DataVolume')
 
1020
        rsrc = self.create_volume(self.t, stack, 'volume')
1230
1021
        self.assertEqual('available', fv.status)
1231
 
        self.create_attachment(t, stack, 'MountPoint')
 
1022
        self.create_attachment(self.t, stack, 'attachment')
1232
1023
 
1233
1024
        props = copy.deepcopy(rsrc.properties.data)
1234
 
        props['Size'] = 2
 
1025
        props['size'] = 2
1235
1026
        after = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(), props)
1236
1027
 
1237
1028
        update_task = scheduler.TaskRunner(rsrc.update, after)
1240
1031
        self.assertEqual((rsrc.UPDATE, rsrc.COMPLETE), rsrc.state)
1241
1032
        self.m.VerifyAll()
1242
1033
 
1243
 
    def test_volume_extend_created_from_snapshot_with_same_size(self):
 
1034
    def test_cinder_volume_extend_created_from_backup_with_same_size(self):
1244
1035
        stack_name = 'test_volume_stack'
1245
1036
        fv = FakeVolumeWithStateTransition('restoring-backup', 'available',
1246
1037
                                           size=2)
1253
1044
        self.cinder_fc.restores.restore('backup-123').AndReturn(fvbr)
1254
1045
        self.cinder_fc.volumes.get('vol-123').AndReturn(fv)
1255
1046
        self.m.StubOutWithMock(fv, 'update')
1256
 
        vol_name = utils.PhysName(stack_name, 'DataVolume')
 
1047
        vol_name = utils.PhysName(stack_name, 'volume')
1257
1048
        fv.update(
1258
 
            display_description=vol_name,
 
1049
            display_description=None,
1259
1050
            display_name=vol_name)
1260
1051
 
1261
1052
        # update script
1262
1053
        self.cinder_fc.volumes.get(fv.id).AndReturn(fv)
1263
1054
        self.m.ReplayAll()
1264
1055
 
1265
 
        t = template_format.parse(volume_template)
1266
 
        t['Resources']['DataVolume']['Properties'].pop('Size')
1267
 
        t['Resources']['DataVolume']['Properties']['SnapshotId'] = 'backup-123'
1268
 
        stack = utils.parse_stack(t, stack_name=stack_name)
 
1056
        self.t['resources']['volume']['properties'] = {
 
1057
            'availability_zone': 'nova',
 
1058
            'backup_id': 'backup-123'
 
1059
        }
 
1060
        stack = utils.parse_stack(self.t, stack_name=stack_name)
1269
1061
 
1270
 
        rsrc = self.create_volume(t, stack, 'DataVolume')
 
1062
        rsrc = self.create_volume(self.t, stack, 'volume')
1271
1063
        self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
1272
1064
        self.assertEqual('available', fv.status)
1273
1065
 
1274
1066
        props = copy.deepcopy(rsrc.properties.data)
1275
 
        props['Size'] = 2
 
1067
        props['size'] = 2
1276
1068
        after = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(), props)
1277
1069
 
1278
1070
        update_task = scheduler.TaskRunner(rsrc.update, after)
1281
1073
        self.assertEqual((rsrc.UPDATE, rsrc.COMPLETE), rsrc.state)
1282
1074
        self.m.VerifyAll()
1283
1075
 
1284
 
    def test_update_cinder_volume(self):
 
1076
    def test_cinder_volume_update_name_and_metadata(self):
1285
1077
        # update the name, description and metadata
1286
1078
        fv = FakeVolume('creating', 'available', size=1, name='my_vol',
1287
1079
                        description='test')
1288
1080
        stack_name = 'test_volume_stack'
1289
1081
        update_name = 'update_name'
1290
 
        meta = {'Key': 'Value'}
1291
 
 
 
1082
        meta = {'Key': 'New Value'}
1292
1083
        update_description = 'update_description'
1293
1084
        kwargs = {
1294
1085
            'display_name': update_name,
1295
1086
            'display_description': update_description
1296
1087
        }
1297
1088
 
1298
 
        cinder.CinderClientPlugin._create().MultipleTimes().AndReturn(
1299
 
            self.cinder_fc)
1300
 
        self.cinder_fc.volumes.create(
1301
 
            availability_zone=None,
1302
 
            size=1,
1303
 
            display_description='test',
1304
 
            display_name='my_vol').AndReturn(fv)
 
1089
        self._mock_create_volume(fv, stack_name)
1305
1090
        self.cinder_fc.volumes.get(fv.id).AndReturn(fv)
1306
1091
        self.cinder_fc.volumes.update(fv, **kwargs).AndReturn(None)
1307
1092
        self.cinder_fc.volumes.update_all_metadata(fv, meta).AndReturn(None)
1308
1093
        self.m.ReplayAll()
1309
1094
 
1310
 
        t = template_format.parse(cinder_volume_template)
1311
 
        stack = utils.parse_stack(t, stack_name=stack_name)
 
1095
        stack = utils.parse_stack(self.t, stack_name=stack_name)
1312
1096
 
1313
 
        rsrc = self.create_cinder_volume(t, stack, 'my_volume')
 
1097
        rsrc = self.create_volume(self.t, stack, 'volume')
1314
1098
 
1315
1099
        props = copy.deepcopy(rsrc.properties.data)
1316
1100
        props['name'] = update_name
1320
1104
        scheduler.TaskRunner(rsrc.update, after)()
1321
1105
 
1322
1106
        self.assertEqual((rsrc.UPDATE, rsrc.COMPLETE), rsrc.state)
 
1107
 
 
1108
    def test_cinder_snapshot(self):
 
1109
        fv = FakeVolume('creating', 'available')
 
1110
        fb = FakeBackup('creating', 'available')
 
1111
        stack_name = 'test_volume_stack'
 
1112
 
 
1113
        cinder.CinderClientPlugin._create().MultipleTimes().AndReturn(
 
1114
            self.cinder_fc)
 
1115
        self.cinder_fc.volumes.create(
 
1116
            size=1, availability_zone='nova', display_name='CustomName',
 
1117
            display_description='CustomDescription').AndReturn(fv)
 
1118
 
 
1119
        self.m.StubOutWithMock(self.cinder_fc.backups, 'create')
 
1120
        self.cinder_fc.backups.create('vol-123').AndReturn(fb)
 
1121
 
 
1122
        self.m.ReplayAll()
 
1123
 
 
1124
        t = template_format.parse(volume_template)
 
1125
        t['Resources']['DataVolume']['Properties'] = {
 
1126
            'size': '1',
 
1127
            'availability_zone': 'nova',
 
1128
            'description': 'CustomDescription',
 
1129
            'name': 'CustomName'
 
1130
        }
 
1131
        stack = utils.parse_stack(t, stack_name=stack_name)
 
1132
 
 
1133
        resource_defns = stack.t.resource_definitions(stack)
 
1134
        rsrc = vol.CinderVolume('DataVolume',
 
1135
                                resource_defns['DataVolume'],
 
1136
                                stack)
 
1137
        scheduler.TaskRunner(rsrc.create)()
 
1138
 
 
1139
        scheduler.TaskRunner(rsrc.snapshot)()
 
1140
 
 
1141
        self.assertEqual((rsrc.SNAPSHOT, rsrc.COMPLETE), rsrc.state)
 
1142
 
 
1143
        self.assertEqual({'backup_id': 'backup-123'},
 
1144
                         db_api.resource_data_get_all(rsrc))
 
1145
 
 
1146
        self.m.VerifyAll()
 
1147
 
 
1148
    def test_cinder_snapshot_error(self):
 
1149
        fv = FakeVolume('creating', 'available')
 
1150
        fb = FakeBackup('creating', 'error')
 
1151
        stack_name = 'test_volume_stack'
 
1152
 
 
1153
        cinder.CinderClientPlugin._create().MultipleTimes().AndReturn(
 
1154
            self.cinder_fc)
 
1155
        self.cinder_fc.volumes.create(
 
1156
            size=1, availability_zone='nova', display_name='CustomName',
 
1157
            display_description='CustomDescription').AndReturn(fv)
 
1158
 
 
1159
        self.m.StubOutWithMock(self.cinder_fc.backups, 'create')
 
1160
        self.cinder_fc.backups.create('vol-123').AndReturn(fb)
 
1161
 
 
1162
        self.m.ReplayAll()
 
1163
 
 
1164
        t = template_format.parse(volume_template)
 
1165
        t['Resources']['DataVolume']['Properties'] = {
 
1166
            'size': '1',
 
1167
            'availability_zone': 'nova',
 
1168
            'description': 'CustomDescription',
 
1169
            'name': 'CustomName'
 
1170
        }
 
1171
        stack = utils.parse_stack(t, stack_name=stack_name)
 
1172
 
 
1173
        resource_defns = stack.t.resource_definitions(stack)
 
1174
        rsrc = vol.CinderVolume('DataVolume',
 
1175
                                resource_defns['DataVolume'],
 
1176
                                stack)
 
1177
        scheduler.TaskRunner(rsrc.create)()
 
1178
 
 
1179
        self.assertRaises(exception.ResourceFailure,
 
1180
                          scheduler.TaskRunner(rsrc.snapshot))
 
1181
 
 
1182
        self.assertEqual((rsrc.SNAPSHOT, rsrc.FAILED), rsrc.state)
 
1183
        self.assertEqual("Error: error", rsrc.status_reason)
 
1184
 
 
1185
        self.assertEqual({}, db_api.resource_data_get_all(rsrc))
 
1186
 
 
1187
        self.m.VerifyAll()
 
1188
 
 
1189
    def test_cinder_volume_attachment_update_device(self):
 
1190
        fv = FakeVolume('creating', 'available')
 
1191
        fva = FakeVolume('attaching', 'in-use')
 
1192
        fva2 = FakeVolume('attaching', 'in-use')
 
1193
        stack_name = 'test_volume_attach_stack'
 
1194
 
 
1195
        self._mock_create_volume(fv, stack_name)
 
1196
 
 
1197
        self._mock_create_server_volume_script(fva)
 
1198
 
 
1199
        # delete script
 
1200
        fva = FakeVolume('in-use', 'available')
 
1201
        self.fc.volumes.get_server_volume(u'WikiDatabase',
 
1202
                                          'vol-123').AndReturn(fva)
 
1203
        self.cinder_fc.volumes.get(fva.id).AndReturn(fva)
 
1204
        self.fc.volumes.delete_server_volume(
 
1205
            'WikiDatabase', 'vol-123').MultipleTimes().AndReturn(None)
 
1206
        self.fc.volumes.get_server_volume(u'WikiDatabase',
 
1207
                                          'vol-123').AndReturn(fva)
 
1208
        self.fc.volumes.get_server_volume(
 
1209
            u'WikiDatabase', 'vol-123').AndRaise(fakes.fake_exception())
 
1210
 
 
1211
        # attach script
 
1212
        self._mock_create_server_volume_script(fva2, device=u'/dev/vdd',
 
1213
                                               update=True)
 
1214
 
 
1215
        self.m.ReplayAll()
 
1216
 
 
1217
        stack = utils.parse_stack(self.t, stack_name=stack_name)
 
1218
 
 
1219
        self.create_volume(self.t, stack, 'volume')
 
1220
        self.assertEqual('available', fv.status)
 
1221
 
 
1222
        rsrc = self.create_attachment(self.t, stack, 'attachment')
 
1223
 
 
1224
        props = copy.deepcopy(rsrc.properties.data)
 
1225
        props['mountpoint'] = '/dev/vdd'
 
1226
        props['volume_id'] = 'vol-123'
 
1227
        after = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(), props)
 
1228
        scheduler.TaskRunner(rsrc.update, after)()
 
1229
 
 
1230
        self.assertEqual((rsrc.UPDATE, rsrc.COMPLETE), rsrc.state)
 
1231
        self.m.VerifyAll()
 
1232
 
 
1233
    def test_cinder_volume_attachment_update_volume(self):
 
1234
        fv = FakeVolume('creating', 'available')
 
1235
        fva = FakeVolume('attaching', 'in-use')
 
1236
        fv2 = FakeVolume('creating', 'available')
 
1237
        fv2.id = 'vol-456'
 
1238
        fv2a = FakeVolume('attaching', 'in-use')
 
1239
        fv2a.id = 'vol-456'
 
1240
        stack_name = 'test_volume_attach_stack'
 
1241
 
 
1242
        self._mock_create_volume(fv, stack_name)
 
1243
 
 
1244
        vol2_name = utils.PhysName(stack_name, 'volume2')
 
1245
        self.cinder_fc.volumes.create(
 
1246
            size=2, availability_zone='nova',
 
1247
            display_description=None,
 
1248
            display_name=vol2_name).AndReturn(fv2)
 
1249
 
 
1250
        self._mock_create_server_volume_script(fva)
 
1251
 
 
1252
        # delete script
 
1253
        fva = FakeVolume('in-use', 'available')
 
1254
        self.fc.volumes.get_server_volume(u'WikiDatabase',
 
1255
                                          'vol-123').AndReturn(fva)
 
1256
        self.cinder_fc.volumes.get(fva.id).AndReturn(fva)
 
1257
        self.fc.volumes.delete_server_volume(
 
1258
            'WikiDatabase', 'vol-123').MultipleTimes().AndReturn(None)
 
1259
        self.fc.volumes.get_server_volume(u'WikiDatabase',
 
1260
                                          'vol-123').AndReturn(fva)
 
1261
        self.fc.volumes.get_server_volume(
 
1262
            u'WikiDatabase', 'vol-123').AndRaise(fakes.fake_exception())
 
1263
 
 
1264
        # attach script
 
1265
        self._mock_create_server_volume_script(fv2a, volume='vol-456',
 
1266
                                               update=True)
 
1267
 
 
1268
        self.m.ReplayAll()
 
1269
 
 
1270
        stack = utils.parse_stack(self.t, stack_name=stack_name)
 
1271
 
 
1272
        self.create_volume(self.t, stack, 'volume')
 
1273
        self.assertEqual('available', fv.status)
 
1274
        self.create_volume(self.t, stack, 'volume2')
 
1275
        self.assertEqual('available', fv2.status)
 
1276
 
 
1277
        rsrc = self.create_attachment(self.t, stack, 'attachment')
 
1278
        self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
 
1279
 
 
1280
        props = copy.deepcopy(rsrc.properties.data)
 
1281
        props['volume_id'] = 'vol-456'
 
1282
        after = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(), props)
 
1283
        scheduler.TaskRunner(rsrc.update, after)()
 
1284
 
 
1285
        self.assertEqual((rsrc.UPDATE, rsrc.COMPLETE), rsrc.state)
 
1286
        self.assertEqual(fv2a.id, rsrc.resource_id)
 
1287
        self.m.VerifyAll()
 
1288
 
 
1289
    def test_cinder_volume_attachment_update_server(self):
 
1290
        fv = FakeVolume('creating', 'available')
 
1291
        fva = FakeVolume('attaching', 'in-use')
 
1292
        fva2 = FakeVolume('attaching', 'in-use')
 
1293
        stack_name = 'test_volume_attach_stack'
 
1294
 
 
1295
        self._mock_create_volume(fv, stack_name)
 
1296
 
 
1297
        self._mock_create_server_volume_script(fva)
 
1298
 
 
1299
        # delete script
 
1300
        fva = FakeVolume('in-use', 'available')
 
1301
        self.fc.volumes.get_server_volume(u'WikiDatabase',
 
1302
                                          'vol-123').AndReturn(fva)
 
1303
        self.cinder_fc.volumes.get(fva.id).AndReturn(fva)
 
1304
        self.fc.volumes.delete_server_volume(
 
1305
            'WikiDatabase', 'vol-123').MultipleTimes().AndReturn(None)
 
1306
        self.fc.volumes.get_server_volume(u'WikiDatabase',
 
1307
                                          'vol-123').AndReturn(fva)
 
1308
        self.fc.volumes.get_server_volume(
 
1309
            u'WikiDatabase', 'vol-123').AndRaise(fakes.fake_exception())
 
1310
 
 
1311
        # attach script
 
1312
        self._mock_create_server_volume_script(fva2, server=u'AnotherServer',
 
1313
                                               update=True)
 
1314
 
 
1315
        self.m.ReplayAll()
 
1316
 
 
1317
        stack = utils.parse_stack(self.t, stack_name=stack_name)
 
1318
 
 
1319
        self.create_volume(self.t, stack, 'volume')
 
1320
        self.assertEqual('available', fv.status)
 
1321
 
 
1322
        rsrc = self.create_attachment(self.t, stack, 'attachment')
 
1323
        self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
 
1324
 
 
1325
        props = copy.deepcopy(rsrc.properties.data)
 
1326
        props['instance_uuid'] = 'AnotherServer'
 
1327
        props['volume_id'] = 'vol-123'
 
1328
        after = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(), props)
 
1329
        scheduler.TaskRunner(rsrc.update, after)()
 
1330
 
 
1331
        self.assertEqual((rsrc.UPDATE, rsrc.COMPLETE), rsrc.state)
1323
1332
        self.m.VerifyAll()
1324
1333
 
1325
1334
 
1330
1339
    def __init__(self, initial_status, final_status, **attrs):
1331
1340
        self.status = initial_status
1332
1341
        self.final_status = final_status
1333
 
        for key, value in attrs.iteritems():
 
1342
        for key, value in six.iteritems(attrs):
1334
1343
            setattr(self, key, value)
1335
1344
 
1336
1345
    def get(self):
1354
1363
            raise exception.Error('life_cycle should not be an empty tuple.')
1355
1364
        self.life_cycle = iter(life_cycle)
1356
1365
        self.status = next(self.life_cycle)
1357
 
        for key, value in attrs.iteritems():
 
1366
        for key, value in six.iteritems(attrs):
1358
1367
            setattr(self, key, value)
1359
1368
 
1360
1369
    def get(self):