blob: 49234574c868f8c4500e0ecc3098dda8f427ac42 [file] [log] [blame]
Steve Bakera5bd9122014-08-11 14:39:00 +12001# Licensed under the Apache License, Version 2.0 (the "License"); you may
2# not use this file except in compliance with the License. You may obtain
3# a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations
11# under the License.
12
13import logging
14import six
15
16from cinderclient import exceptions as cinder_exceptions
17
Steve Baker50d3e8c2014-10-21 11:08:50 +130018from heat_integrationtests.common import exceptions
Steve Bakera5bd9122014-08-11 14:39:00 +120019from heat_integrationtests.common import test
20
21LOG = logging.getLogger(__name__)
22
23
24class VolumeBackupRestoreIntegrationTest(test.HeatIntegrationTest):
25
26 def setUp(self):
27 super(VolumeBackupRestoreIntegrationTest, self).setUp()
28 self.client = self.orchestration_client
29 if self.conf.keypair_name:
30 self.keypair_name = self.conf.keypair_name
31 else:
32 self.keypair = self.create_keypair()
33 self.keypair_name = self.keypair.id
34 self.volume_description = 'A test volume description 123'
35 self.volume_size = self.conf.volume_size
36
37 def _cinder_verify(self, volume_id, expected_status='available'):
38 self.assertIsNotNone(volume_id)
39 volume = self.volume_client.volumes.get(volume_id)
40 self.assertIsNotNone(volume)
41 self.assertEqual(expected_status, volume.status)
42 self.assertEqual(self.volume_size, volume.size)
43 self.assertEqual(self.volume_description,
44 volume.display_description)
45
46 def _outputs_verify(self, stack, expected_status='available'):
47 self.assertEqual(expected_status,
48 self._stack_output(stack, 'status'))
49 self.assertEqual(six.text_type(self.volume_size),
50 self._stack_output(stack, 'size'))
51 self.assertEqual(self.volume_description,
52 self._stack_output(stack, 'display_description'))
53
54 def _create_stack(self, template_name, add_parameters={}):
55 # TODO(shardy): refactor this into a generic base-class helper
56 net = self._get_default_network()
57 stack_name = self._stack_rand_name()
58 template = self._load_template(__file__, template_name)
59 parameters = {'key_name': self.keypair_name,
60 'instance_type': self.conf.instance_type,
61 'image_id': self.conf.minimal_image_ref,
62 'volume_description': self.volume_description,
63 'timeout': self.conf.build_timeout,
64 'network': net['id']}
65 parameters.update(add_parameters)
66 ret_stack = self.client.stacks.create(
67 stack_name=stack_name,
68 template=template,
69 parameters=parameters)
70 stack_id = ret_stack['stack']['id']
71 stack = self.client.stacks.get(stack_id)
72 self.assertIsNotNone(stack)
73 stack_identifier = '%s/%s' % (stack_name, stack.id)
74
75 self.addCleanup(self._stack_delete, stack_identifier)
76 self._wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
77 return stack, stack_identifier
78
79 def test_cinder_volume_create_backup_restore(self):
80 """Ensure the 'Snapshot' deletion policy works.
81
82 This requires a more complex test, but it tests several aspects
83 of the heat cinder resources:
84 1. Create a volume, attach it to an instance, write some data to it
85 2. Delete the stack, with 'Snapshot' specified, creates a backup
86 3. Check the snapshot has created a volume backup
87 4. Create a new stack, where the volume is created from the backup
88 5. Verify the test data written in (1) is present in the new volume
89 """
90 stack, stack_identifier = self._create_stack(
91 template_name='test_volumes_delete_snapshot.yaml',
92 add_parameters={'volume_size': self.volume_size})
93
94 # Verify with cinder that the volume exists, with matching details
95 volume_id = self._stack_output(stack, 'volume_id')
96 self._cinder_verify(volume_id, expected_status='in-use')
97
98 # Verify the stack outputs are as expected
99 self._outputs_verify(stack, expected_status='in-use')
100
101 # Delete the stack and ensure a backup is created for volume_id
102 # but the volume itself is gone
103 self.client.stacks.delete(stack_identifier)
104 self._wait_for_stack_status(stack_identifier, 'DELETE_COMPLETE')
105 self.assertRaises(cinder_exceptions.NotFound,
106 self.volume_client.volumes.get,
107 volume_id)
108
109 backups = self.volume_client.backups.list()
110 self.assertIsNotNone(backups)
111 backups_filtered = [b for b in backups if b.volume_id == volume_id]
112 self.assertEqual(1, len(backups_filtered))
113 backup = backups_filtered[0]
114 self.addCleanup(self.volume_client.backups.delete, backup.id)
115
116 # Now, we create another stack where the volume is created from the
117 # backup created by the previous stack
Steve Baker50d3e8c2014-10-21 11:08:50 +1300118 try:
119 stack2, stack_identifier2 = self._create_stack(
120 template_name='test_volumes_create_from_backup.yaml',
121 add_parameters={'backup_id': backup.id})
122 except exceptions.StackBuildErrorException as e:
123 LOG.error("Halting test due to bug: #1382300")
124 LOG.exception(e)
125 return
Steve Bakera5bd9122014-08-11 14:39:00 +1200126
127 # Verify with cinder that the volume exists, with matching details
128 volume_id2 = self._stack_output(stack2, 'volume_id')
129 self._cinder_verify(volume_id2, expected_status='in-use')
130
131 # Verify the stack outputs are as expected
132 self._outputs_verify(stack2, expected_status='in-use')
133 testfile_data = self._stack_output(stack2, 'testfile_data')
134 self.assertEqual('{"instance1": "Volume Data:ateststring"}',
135 testfile_data)
136
137 # Delete the stack and ensure the volume is gone
138 self.client.stacks.delete(stack_identifier2)
139 self._wait_for_stack_status(stack_identifier2, 'DELETE_COMPLETE')
140 self.assertRaises(cinder_exceptions.NotFound,
141 self.volume_client.volumes.get,
142 volume_id2)