From 4894a91ac2ed8d5f7cf345efd3b7d9b3cd67dd4e Mon Sep 17 00:00:00 2001 From: Evgeny Antyshev Date: Mon, 21 Nov 2016 12:17:18 +0000 Subject: [PATCH] Make get_partitions() work for partitioned disks In general case, attached disks could be partitioned, and this leads to multiple records in /proc/partitions, for my laptop which is: evgeny@eantyshev2:~$ cat /proc/partitions major minor #blocks name 8 0 125034840 sda 8 1 524288 sda1 8 2 249856 sda2 8 3 124259328 sda3 8 16 976762584 sdb 11 0 1048575 sr0 252 0 1084366848 dm-0 252 1 16650240 dm-1 QEMU adds block devices as unpartitioned disks, so that we have 1 disk <-> 1 partition match. But this is just an implementation specific coincidence. Because the attached disk can have GPT table and a primary partition covering available disk space, and in this case it would mean 2 extra devices. Namely, to run Tempest on Virtuozzo containers, we should allow for partitioned disks attached. CT-f9e98104 /# cat /proc/partitions major minor #blocks name 182 686608 2097152 ploop42913 182 686609 2095104 ploop42913p1 182 506688 1048576 ploop31668 182 506689 1046528 ploop31668p1 Here we see 2 devices for each disk: root disk block device ploop31668, and partition block device ploop31668p1. We only want to see root device for each disk, not the partition ones, or some testcases don't work (test_verify_created_server_ephemeral_disk naturally expects device appearance of 1 extra device). Change-Id: Icd0043b661c41a51acf62cc07cb80c2e9bae56d4 --- .../api/compute/servers/test_create_server.py | 6 +++--- .../api/compute/volumes/test_attach_volume.py | 10 +++++----- tempest/common/utils/linux/remote_client.py | 19 +++++++++++++++---- tempest/scenario/test_minimum_basic.py | 8 ++++---- tempest/scenario/test_stamp_pattern.py | 6 +++--- .../common/utils/linux/test_remote_client.py | 19 +++++++++++++------ 6 files changed, 43 insertions(+), 25 deletions(-) diff --git a/tempest/api/compute/servers/test_create_server.py b/tempest/api/compute/servers/test_create_server.py index 2f43157f77..a05cb89f00 100644 --- a/tempest/api/compute/servers/test_create_server.py +++ b/tempest/api/compute/servers/test_create_server.py @@ -312,7 +312,7 @@ class ServersWithSpecificFlavorTestJSON(base.BaseV2ComputeAdminTest): self.validation_resources['keypair']['private_key'], server=server_no_eph_disk, servers_client=self.client) - partition_num = len(linux_client.get_partitions().split('\n')) + disks_num = len(linux_client.get_disks().split('\n')) # Explicit server deletion necessary for Juno compatibility self.client.delete_server(server_no_eph_disk['id']) @@ -332,8 +332,8 @@ class ServersWithSpecificFlavorTestJSON(base.BaseV2ComputeAdminTest): self.validation_resources['keypair']['private_key'], server=server_with_eph_disk, servers_client=self.client) - partition_num_emph = len(linux_client.get_partitions().split('\n')) - self.assertEqual(partition_num + 1, partition_num_emph) + disks_num_eph = len(linux_client.get_disks().split('\n')) + self.assertEqual(disks_num + 1, disks_num_eph) class ServersTestManualDisk(ServersTestJSON): diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py index d4831b155e..4ba9c5e475 100644 --- a/tempest/api/compute/volumes/test_attach_volume.py +++ b/tempest/api/compute/volumes/test_attach_volume.py @@ -109,9 +109,9 @@ class AttachVolumeTestJSON(base.BaseV2ComputeTest): server=server, servers_client=self.servers_client) - partitions = linux_client.get_partitions() - device_name_to_match = ' ' + self.device + '\n' - self.assertIn(device_name_to_match, partitions) + disks = linux_client.get_disks() + device_name_to_match = '\n' + self.device + ' ' + self.assertIn(device_name_to_match, disks) self._detach(server['id'], volume['id']) self.attachment = None @@ -132,8 +132,8 @@ class AttachVolumeTestJSON(base.BaseV2ComputeTest): server=server, servers_client=self.servers_client) - partitions = linux_client.get_partitions() - self.assertNotIn(device_name_to_match, partitions) + disks = linux_client.get_disks() + self.assertNotIn(device_name_to_match, disks) @test.idempotent_id('7fa563fe-f0f7-43eb-9e22-a1ece036b513') def test_list_get_volume_attachments(self): diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py index 9ec217f9c9..d8993bbf0e 100644 --- a/tempest/common/utils/linux/remote_client.py +++ b/tempest/common/utils/linux/remote_client.py @@ -112,11 +112,22 @@ class RemoteClient(object): output = self.exec_command('grep -c ^processor /proc/cpuinfo') return int(output) - def get_partitions(self): - # Return the contents of /proc/partitions - command = 'cat /proc/partitions' + def get_disks(self): + # Select root disk devices as shown by lsblk + command = 'lsblk -lb --nodeps' output = self.exec_command(command) - return output + selected = [] + pos = None + for l in output.splitlines(): + if pos is None and l.find("TYPE") > 0: + pos = l.find("TYPE") + # Show header line too + selected.append(l) + # lsblk lists disk type in a column right-aligned with TYPE + elif pos > 0 and l[pos:pos + 4] == "disk": + selected.append(l) + + return "\n".join(selected) def get_boot_time(self): cmd = 'cut -f1 -d. /proc/uptime' diff --git a/tempest/scenario/test_minimum_basic.py b/tempest/scenario/test_minimum_basic.py index 3ac6759787..bf52211fe7 100644 --- a/tempest/scenario/test_minimum_basic.py +++ b/tempest/scenario/test_minimum_basic.py @@ -66,10 +66,10 @@ class TestMinimumBasicScenario(manager.ScenarioTest): waiters.wait_for_server_status(self.servers_client, server['id'], 'ACTIVE') - def check_partitions(self): + def check_disks(self): # NOTE(andreaf) The device name may be different on different guest OS - partitions = self.linux_client.get_partitions() - self.assertEqual(1, partitions.count(CONF.compute.volume_device_name)) + disks = self.linux_client.get_disks() + self.assertEqual(1, disks.count(CONF.compute.volume_device_name)) def create_and_add_security_group_to_server(self, server): secgroup = self._create_security_group() @@ -145,7 +145,7 @@ class TestMinimumBasicScenario(manager.ScenarioTest): self.linux_client = self.get_remote_client( floating_ip['ip'], private_key=keypair['private_key']) - self.check_partitions() + self.check_disks() # delete the floating IP, this should refresh the server addresses self.compute_floating_ips_client.delete_floating_ip(floating_ip['id']) diff --git a/tempest/scenario/test_stamp_pattern.py b/tempest/scenario/test_stamp_pattern.py index 0f2c78c974..dff00e760a 100644 --- a/tempest/scenario/test_stamp_pattern.py +++ b/tempest/scenario/test_stamp_pattern.py @@ -85,9 +85,9 @@ class TestStampPattern(manager.ScenarioTest): ssh = self.get_remote_client(ip_address, private_key=private_key) def _func(): - part = ssh.get_partitions() - LOG.debug("Partitions:%s" % part) - return CONF.compute.volume_device_name in part + disks = ssh.get_disks() + LOG.debug("Disks: %s" % disks) + return CONF.compute.volume_device_name in disks if not test_utils.call_until_true(_func, CONF.compute.build_timeout, diff --git a/tempest/tests/common/utils/linux/test_remote_client.py b/tempest/tests/common/utils/linux/test_remote_client.py index e59e08f522..e4f4c041bd 100644 --- a/tempest/tests/common/utils/linux/test_remote_client.py +++ b/tempest/tests/common/utils/linux/test_remote_client.py @@ -107,13 +107,20 @@ class TestRemoteClient(base.TestCase): self.assertEqual(self.conn.get_number_of_vcpus(), 16) self._assert_exec_called_with('grep -c ^processor /proc/cpuinfo') - def test_get_partitions(self): - proc_partitions = """major minor #blocks name + def test_get_disks(self): + output_lsblk = """\ +NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT +sda 8:0 0 128035676160 0 disk +sdb 8:16 0 1000204886016 0 disk +sr0 11:0 1 1073741312 0 rom""" + result = """\ +NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT +sda 8:0 0 128035676160 0 disk +sdb 8:16 0 1000204886016 0 disk""" -8 0 1048576 vda""" - self.ssh_mock.mock.exec_command.return_value = proc_partitions - self.assertEqual(self.conn.get_partitions(), proc_partitions) - self._assert_exec_called_with('cat /proc/partitions') + self.ssh_mock.mock.exec_command.return_value = output_lsblk + self.assertEqual(self.conn.get_disks(), result) + self._assert_exec_called_with('lsblk -lb --nodeps') def test_get_boot_time(self): booted_at = 10000