Rajat Dhasmana | 21d63a3 | 2020-01-14 17:41:22 +0000 | [diff] [blame] | 1 | # Copyright 2020 Red Hat, Inc. |
| 2 | # All Rights Reserved. |
| 3 | # |
| 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may |
| 5 | # not use this file except in compliance with the License. You may obtain |
| 6 | # a copy of the License at |
| 7 | # |
| 8 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | # |
| 10 | # Unless required by applicable law or agreed to in writing, software |
| 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| 13 | # License for the specific language governing permissions and limitations |
| 14 | # under the License. |
| 15 | |
Rajat Dhasmana | 21d63a3 | 2020-01-14 17:41:22 +0000 | [diff] [blame] | 16 | from tempest.common import utils |
Rajat Dhasmana | d9e5925 | 2021-05-11 16:03:47 -0400 | [diff] [blame] | 17 | from tempest import config |
| 18 | from tempest.lib.common.utils import test_utils |
Rajat Dhasmana | 21d63a3 | 2020-01-14 17:41:22 +0000 | [diff] [blame] | 19 | from tempest.lib import decorators |
Rajat Dhasmana | d9e5925 | 2021-05-11 16:03:47 -0400 | [diff] [blame] | 20 | from tempest.lib import exceptions as lib_exc |
Rajat Dhasmana | 21d63a3 | 2020-01-14 17:41:22 +0000 | [diff] [blame] | 21 | |
Luigi Toscano | 3c5c8a2 | 2021-02-23 10:24:01 +0100 | [diff] [blame] | 22 | from cinder_tempest_plugin.scenario import manager |
| 23 | |
Rajat Dhasmana | d9e5925 | 2021-05-11 16:03:47 -0400 | [diff] [blame] | 24 | CONF = config.CONF |
| 25 | |
Rajat Dhasmana | 21d63a3 | 2020-01-14 17:41:22 +0000 | [diff] [blame] | 26 | |
| 27 | class SnapshotDataIntegrityTests(manager.ScenarioTest): |
| 28 | |
| 29 | def setUp(self): |
| 30 | super(SnapshotDataIntegrityTests, self).setUp() |
| 31 | self.keypair = self.create_keypair() |
| 32 | self.security_group = self._create_security_group() |
| 33 | |
Rajat Dhasmana | d9e5925 | 2021-05-11 16:03:47 -0400 | [diff] [blame] | 34 | def _attached_volume_name( |
| 35 | self, disks_list_before_attach, ip_address, private_key): |
| 36 | ssh = self.get_remote_client(ip_address, private_key=private_key) |
| 37 | |
| 38 | def _wait_for_volume_available_on_system(): |
| 39 | disks_list_after_attach = ssh.list_disks() |
| 40 | return len(disks_list_after_attach) > len(disks_list_before_attach) |
| 41 | |
| 42 | if not test_utils.call_until_true(_wait_for_volume_available_on_system, |
| 43 | CONF.compute.build_timeout, |
| 44 | CONF.compute.build_interval): |
| 45 | raise lib_exc.TimeoutException |
| 46 | |
| 47 | disks_list_after_attach = ssh.list_disks() |
| 48 | volume_name = [item for item in disks_list_after_attach |
| 49 | if item not in disks_list_before_attach][0] |
| 50 | return volume_name |
| 51 | |
| 52 | def _get_file_md5(self, ip_address, filename, dev_name=None, |
| 53 | mount_path='/mnt', private_key=None, server=None): |
| 54 | |
Rajat Dhasmana | 21d63a3 | 2020-01-14 17:41:22 +0000 | [diff] [blame] | 55 | ssh_client = self.get_remote_client(ip_address, |
| 56 | private_key=private_key, |
| 57 | server=server) |
Rajat Dhasmana | d9e5925 | 2021-05-11 16:03:47 -0400 | [diff] [blame] | 58 | if dev_name is not None: |
| 59 | ssh_client.exec_command('sudo mount /dev/%s %s' % (dev_name, |
| 60 | mount_path)) |
Rajat Dhasmana | 21d63a3 | 2020-01-14 17:41:22 +0000 | [diff] [blame] | 61 | |
| 62 | md5_sum = ssh_client.exec_command( |
| 63 | 'sudo md5sum %s/%s|cut -c 1-32' % (mount_path, filename)) |
Rajat Dhasmana | d9e5925 | 2021-05-11 16:03:47 -0400 | [diff] [blame] | 64 | if dev_name is not None: |
| 65 | ssh_client.exec_command('sudo umount %s' % mount_path) |
Rajat Dhasmana | 21d63a3 | 2020-01-14 17:41:22 +0000 | [diff] [blame] | 66 | return md5_sum |
| 67 | |
Rajat Dhasmana | d9e5925 | 2021-05-11 16:03:47 -0400 | [diff] [blame] | 68 | def _count_files(self, ip_address, dev_name=None, mount_path='/mnt', |
| 69 | private_key=None, server=None): |
Rajat Dhasmana | 21d63a3 | 2020-01-14 17:41:22 +0000 | [diff] [blame] | 70 | ssh_client = self.get_remote_client(ip_address, |
| 71 | private_key=private_key, |
| 72 | server=server) |
Rajat Dhasmana | d9e5925 | 2021-05-11 16:03:47 -0400 | [diff] [blame] | 73 | if dev_name is not None: |
| 74 | ssh_client.exec_command('sudo mount /dev/%s %s' % (dev_name, |
| 75 | mount_path)) |
Rajat Dhasmana | 21d63a3 | 2020-01-14 17:41:22 +0000 | [diff] [blame] | 76 | count = ssh_client.exec_command('sudo ls -l %s | wc -l' % mount_path) |
Rajat Dhasmana | d9e5925 | 2021-05-11 16:03:47 -0400 | [diff] [blame] | 77 | if dev_name is not None: |
| 78 | ssh_client.exec_command('sudo umount %s' % mount_path) |
| 79 | # We subtract 2 from the count since `wc -l` also includes the count |
| 80 | # of new line character and while creating the filesystem, a |
| 81 | # lost+found folder is also created |
| 82 | return int(count) - 2 |
Rajat Dhasmana | 21d63a3 | 2020-01-14 17:41:22 +0000 | [diff] [blame] | 83 | |
Rajat Dhasmana | d9e5925 | 2021-05-11 16:03:47 -0400 | [diff] [blame] | 84 | def _make_fs(self, ip_address, private_key, server, dev_name, fs='ext4'): |
Rajat Dhasmana | 21d63a3 | 2020-01-14 17:41:22 +0000 | [diff] [blame] | 85 | ssh_client = self.get_remote_client(ip_address, |
| 86 | private_key=private_key, |
| 87 | server=server) |
| 88 | |
Rajat Dhasmana | d9e5925 | 2021-05-11 16:03:47 -0400 | [diff] [blame] | 89 | ssh_client.make_fs(dev_name, fs=fs) |
| 90 | |
| 91 | def create_md5_new_file(self, ip_address, filename, dev_name=None, |
| 92 | mount_path='/mnt', private_key=None, server=None): |
| 93 | ssh_client = self.get_remote_client(ip_address, |
| 94 | private_key=private_key, |
| 95 | server=server) |
| 96 | |
| 97 | if dev_name is not None: |
| 98 | ssh_client.exec_command('sudo mount /dev/%s %s' % (dev_name, |
| 99 | mount_path)) |
Rajat Dhasmana | 21d63a3 | 2020-01-14 17:41:22 +0000 | [diff] [blame] | 100 | ssh_client.exec_command( |
| 101 | 'sudo dd bs=1024 count=100 if=/dev/urandom of=/%s/%s' % |
| 102 | (mount_path, filename)) |
| 103 | md5 = ssh_client.exec_command( |
| 104 | 'sudo md5sum -b %s/%s|cut -c 1-32' % (mount_path, filename)) |
| 105 | ssh_client.exec_command('sudo sync') |
Rajat Dhasmana | d9e5925 | 2021-05-11 16:03:47 -0400 | [diff] [blame] | 106 | if dev_name is not None: |
| 107 | ssh_client.exec_command('sudo umount %s' % mount_path) |
Rajat Dhasmana | 21d63a3 | 2020-01-14 17:41:22 +0000 | [diff] [blame] | 108 | return md5 |
| 109 | |
Rajat Dhasmana | d9e5925 | 2021-05-11 16:03:47 -0400 | [diff] [blame] | 110 | def get_md5_from_file(self, instance, instance_ip, filename, |
| 111 | dev_name=None): |
Rajat Dhasmana | 21d63a3 | 2020-01-14 17:41:22 +0000 | [diff] [blame] | 112 | |
| 113 | md5_sum = self._get_file_md5(instance_ip, filename=filename, |
Rajat Dhasmana | d9e5925 | 2021-05-11 16:03:47 -0400 | [diff] [blame] | 114 | dev_name=dev_name, |
Rajat Dhasmana | 21d63a3 | 2020-01-14 17:41:22 +0000 | [diff] [blame] | 115 | private_key=self.keypair['private_key'], |
| 116 | server=instance) |
Rajat Dhasmana | d9e5925 | 2021-05-11 16:03:47 -0400 | [diff] [blame] | 117 | count = self._count_files(instance_ip, dev_name=dev_name, |
Rajat Dhasmana | 21d63a3 | 2020-01-14 17:41:22 +0000 | [diff] [blame] | 118 | private_key=self.keypair['private_key'], |
| 119 | server=instance) |
| 120 | return count, md5_sum |
| 121 | |
Rajat Dhasmana | d9e5925 | 2021-05-11 16:03:47 -0400 | [diff] [blame] | 122 | def _attach_and_get_volume_device_name(self, server, volume, instance_ip, |
| 123 | private_key): |
| 124 | ssh_client = self.get_remote_client( |
| 125 | instance_ip, private_key=private_key, |
| 126 | server=server) |
| 127 | # List disks before volume attachment |
| 128 | disks_list_before_attach = ssh_client.list_disks() |
| 129 | # Attach volume |
| 130 | volume = self.nova_volume_attach(server, volume) |
| 131 | # Find the difference between disks before and after attachment that |
| 132 | # gives us the volume device name |
| 133 | volume_device_name = self._attached_volume_name( |
| 134 | disks_list_before_attach, instance_ip, private_key) |
| 135 | return volume_device_name |
| 136 | |
Rajat Dhasmana | 21d63a3 | 2020-01-14 17:41:22 +0000 | [diff] [blame] | 137 | @decorators.idempotent_id('ff10644e-5a70-4a9f-9801-8204bb81fb61') |
| 138 | @utils.services('compute', 'volume', 'image', 'network') |
| 139 | def test_snapshot_data_integrity(self): |
| 140 | """This test checks the data integrity after creating and restoring |
| 141 | |
| 142 | snapshots. The procedure is as follows: |
| 143 | |
Rajat Dhasmana | d9e5925 | 2021-05-11 16:03:47 -0400 | [diff] [blame] | 144 | 1) Create an instance with ephemeral disk |
| 145 | 2) Create a volume, attach it to the instance and create a filesystem |
| 146 | on it and mount it |
| 147 | 3) Mount the volume, create a file and write data into it, Unmount it |
Rajat Dhasmana | 21d63a3 | 2020-01-14 17:41:22 +0000 | [diff] [blame] | 148 | 4) create snapshot |
| 149 | 5) repeat 3 and 4 two more times (simply creating 3 snapshots) |
| 150 | |
Rajat Dhasmana | d9e5925 | 2021-05-11 16:03:47 -0400 | [diff] [blame] | 151 | Now create volume from the snapshots one by one, attach it to the |
| 152 | instance and check the number of files and file content at each |
Rajat Dhasmana | 21d63a3 | 2020-01-14 17:41:22 +0000 | [diff] [blame] | 153 | point when snapshot was created. |
| 154 | """ |
| 155 | |
Rajat Dhasmana | d9e5925 | 2021-05-11 16:03:47 -0400 | [diff] [blame] | 156 | # Create an instance |
| 157 | server = self.create_server( |
| 158 | key_name=self.keypair['name'], |
| 159 | security_groups=[{'name': self.security_group['name']}]) |
Rajat Dhasmana | 21d63a3 | 2020-01-14 17:41:22 +0000 | [diff] [blame] | 160 | |
Rajat Dhasmana | d9e5925 | 2021-05-11 16:03:47 -0400 | [diff] [blame] | 161 | # Create an empty volume |
| 162 | volume = self.create_volume() |
Rajat Dhasmana | 21d63a3 | 2020-01-14 17:41:22 +0000 | [diff] [blame] | 163 | |
| 164 | instance_ip = self.get_server_ip(server) |
| 165 | |
Rajat Dhasmana | d9e5925 | 2021-05-11 16:03:47 -0400 | [diff] [blame] | 166 | # Attach volume to instance and find it's device name (eg: /dev/vdb) |
| 167 | volume_device_name = self._attach_and_get_volume_device_name( |
| 168 | server, volume, instance_ip, self.keypair['private_key']) |
| 169 | |
| 170 | # Create filesystem on the volume |
| 171 | self._make_fs(instance_ip, self.keypair['private_key'], server, |
| 172 | volume_device_name) |
| 173 | |
Rajat Dhasmana | 21d63a3 | 2020-01-14 17:41:22 +0000 | [diff] [blame] | 174 | # Write data to volume |
| 175 | file1_md5 = self.create_md5_new_file( |
Rajat Dhasmana | d9e5925 | 2021-05-11 16:03:47 -0400 | [diff] [blame] | 176 | instance_ip, dev_name=volume_device_name, filename="file1", |
Rajat Dhasmana | 21d63a3 | 2020-01-14 17:41:22 +0000 | [diff] [blame] | 177 | private_key=self.keypair['private_key'], |
| 178 | server=instance_ip) |
| 179 | |
| 180 | # Create first snapshot |
| 181 | snapshot1 = self.create_volume_snapshot(volume['id'], force=True) |
| 182 | |
| 183 | # Write data to volume |
| 184 | file2_md5 = self.create_md5_new_file( |
Rajat Dhasmana | d9e5925 | 2021-05-11 16:03:47 -0400 | [diff] [blame] | 185 | instance_ip, dev_name=volume_device_name, filename="file2", |
Rajat Dhasmana | 21d63a3 | 2020-01-14 17:41:22 +0000 | [diff] [blame] | 186 | private_key=self.keypair['private_key'], |
| 187 | server=instance_ip) |
| 188 | |
| 189 | # Create second snapshot |
| 190 | snapshot2 = self.create_volume_snapshot(volume['id'], force=True) |
| 191 | |
| 192 | # Write data to volume |
| 193 | file3_md5 = self.create_md5_new_file( |
Rajat Dhasmana | d9e5925 | 2021-05-11 16:03:47 -0400 | [diff] [blame] | 194 | instance_ip, dev_name=volume_device_name, filename="file3", |
Rajat Dhasmana | 21d63a3 | 2020-01-14 17:41:22 +0000 | [diff] [blame] | 195 | private_key=self.keypair['private_key'], |
| 196 | server=instance_ip) |
| 197 | |
| 198 | # Create third snapshot |
| 199 | snapshot3 = self.create_volume_snapshot(volume['id'], force=True) |
| 200 | |
Rajat Dhasmana | d9e5925 | 2021-05-11 16:03:47 -0400 | [diff] [blame] | 201 | # Detach the volume |
| 202 | self.nova_volume_detach(server, volume) |
| 203 | |
| 204 | # Create volume from snapshot, attach it to instance and check file |
| 205 | # and contents for snap1 |
| 206 | volume_snap_1 = self.create_volume(snapshot_id=snapshot1['id']) |
| 207 | volume_device_name = self._attach_and_get_volume_device_name( |
| 208 | server, volume_snap_1, instance_ip, self.keypair['private_key']) |
| 209 | count_snap_1, md5_file_1 = self.get_md5_from_file( |
| 210 | server, instance_ip, 'file1', dev_name=volume_device_name) |
| 211 | # Detach the volume |
| 212 | self.nova_volume_detach(server, volume_snap_1) |
Rajat Dhasmana | 21d63a3 | 2020-01-14 17:41:22 +0000 | [diff] [blame] | 213 | |
| 214 | self.assertEqual(count_snap_1, 1) |
| 215 | self.assertEqual(file1_md5, md5_file_1) |
| 216 | |
Rajat Dhasmana | d9e5925 | 2021-05-11 16:03:47 -0400 | [diff] [blame] | 217 | # Create volume from snapshot, attach it to instance and check file |
| 218 | # and contents for snap2 |
| 219 | volume_snap_2 = self.create_volume(snapshot_id=snapshot2['id']) |
| 220 | volume_device_name = self._attach_and_get_volume_device_name( |
| 221 | server, volume_snap_2, instance_ip, self.keypair['private_key']) |
| 222 | count_snap_2, md5_file_2 = self.get_md5_from_file( |
| 223 | server, instance_ip, 'file2', dev_name=volume_device_name) |
| 224 | # Detach the volume |
| 225 | self.nova_volume_detach(server, volume_snap_2) |
Rajat Dhasmana | 21d63a3 | 2020-01-14 17:41:22 +0000 | [diff] [blame] | 226 | |
| 227 | self.assertEqual(count_snap_2, 2) |
| 228 | self.assertEqual(file2_md5, md5_file_2) |
| 229 | |
Rajat Dhasmana | d9e5925 | 2021-05-11 16:03:47 -0400 | [diff] [blame] | 230 | # Create volume from snapshot, attach it to instance and check file |
| 231 | # and contents for snap3 |
| 232 | volume_snap_3 = self.create_volume(snapshot_id=snapshot3['id']) |
| 233 | volume_device_name = self._attach_and_get_volume_device_name( |
| 234 | server, volume_snap_3, instance_ip, self.keypair['private_key']) |
| 235 | count_snap_3, md5_file_3 = self.get_md5_from_file( |
| 236 | server, instance_ip, 'file3', dev_name=volume_device_name) |
| 237 | # Detach the volume |
| 238 | self.nova_volume_detach(server, volume_snap_3) |
Rajat Dhasmana | 21d63a3 | 2020-01-14 17:41:22 +0000 | [diff] [blame] | 239 | |
| 240 | self.assertEqual(count_snap_3, 3) |
| 241 | self.assertEqual(file3_md5, md5_file_3) |