From 8c1d4554ae60aad799826f1d8967a69bdf3fd017 Mon Sep 17 00:00:00 2001 From: wangyaoguang Date: Fri, 15 Jul 2016 22:15:29 +0800 Subject: Support Storage Capacity Test It measures disk size, block size and disk utilization. JIRA: YARDSTICK-284 Change-Id: I61b3fb8a35da41c77450c157f843fb853d77dddd Signed-off-by: wangyaoguang --- samples/storagecapacity.yaml | 24 ++++ .../scenarios/storage/test_storagecapacity.py | 98 +++++++++++++++ .../scenarios/storage/storagecapacity.bash | 69 +++++++++++ .../benchmark/scenarios/storage/storagecapacity.py | 133 +++++++++++++++++++++ 4 files changed, 324 insertions(+) create mode 100644 samples/storagecapacity.yaml create mode 100644 tests/unit/benchmark/scenarios/storage/test_storagecapacity.py create mode 100644 yardstick/benchmark/scenarios/storage/storagecapacity.bash create mode 100644 yardstick/benchmark/scenarios/storage/storagecapacity.py diff --git a/samples/storagecapacity.yaml b/samples/storagecapacity.yaml new file mode 100644 index 000000000..93394be12 --- /dev/null +++ b/samples/storagecapacity.yaml @@ -0,0 +1,24 @@ +--- +# Sample benchmark task config file +# Measure storage capacity and scale. +# Including number of PVs, volume of disk size, +# and block size of each device. + +schema: "yardstick:task:0.1" + +scenarios: +- + type: StorageCapacity + options: + test_type: "disk_size" + + host: node5.LF + + runner: + type: Iteration + iterations: 1 + +context: + type: Node + name: LF + file: /root/yardstick/etc/yardstick/nodes/compass_sclab_virtual/pod.yaml diff --git a/tests/unit/benchmark/scenarios/storage/test_storagecapacity.py b/tests/unit/benchmark/scenarios/storage/test_storagecapacity.py new file mode 100644 index 000000000..cad5ba1d1 --- /dev/null +++ b/tests/unit/benchmark/scenarios/storage/test_storagecapacity.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python + +############################################################################## +# Copyright (c) 2016 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +# Unittest for yardstick.benchmark.scenarios.storage.storagecapacity.StorageCapacity + +import mock +import unittest +import os +import json + +from yardstick.benchmark.scenarios.storage import storagecapacity + +DISK_SIZE_SAMPLE_OUTPUT = '{"Numberf of devides": "2", "Total disk size": "1024000000 bytes"}' +BLOCK_SIZE_SAMPLE_OUTPUT = '{"/dev/sda": 1024, "/dev/sdb": 4096}' +DISK_UTIL_RAW_OUTPUT = "vda 10.00\nvda 0.00" +DISK_UTIL_SAMPLE_OUTPUT = '{"vda": {"avg_util": 5.0, "max_util": 10.0, "min_util": 0.0}}' + +@mock.patch('yardstick.benchmark.scenarios.storage.storagecapacity.ssh') +class StorageCapacityTestCase(unittest.TestCase): + + def setUp(self): + self.scn = { + "options": { + 'test_type': 'disk_size' + } + } + self.ctx = { + "host": { + 'ip': '172.16.0.137', + 'user': 'cirros', + 'password': "root" + } + } + self.result = {} + + def test_capacity_successful_setup(self, mock_ssh): + c = storagecapacity.StorageCapacity(self.scn, self.ctx) + + mock_ssh.SSH().execute.return_value = (0, '', '') + c.setup() + self.assertIsNotNone(c.client) + self.assertTrue(c.setup_done) + + def test_capacity_disk_size_successful(self, mock_ssh): + c = storagecapacity.StorageCapacity(self.scn, self.ctx) + + mock_ssh.SSH().execute.return_value = (0, DISK_SIZE_SAMPLE_OUTPUT, '') + c.run(self.result) + expected_result = json.loads(DISK_SIZE_SAMPLE_OUTPUT) + self.assertEqual(self.result, expected_result) + + def test_capacity_block_size_successful(self, mock_ssh): + args = { + "options": { + 'test_type': 'block_size' + } + } + c = storagecapacity.StorageCapacity(args, self.ctx) + + mock_ssh.SSH().execute.return_value = (0, BLOCK_SIZE_SAMPLE_OUTPUT, '') + c.run(self.result) + expected_result = json.loads(BLOCK_SIZE_SAMPLE_OUTPUT) + self.assertEqual(self.result, expected_result) + + def test_capacity_disk_utilization_successful(self, mock_ssh): + args = { + "options": { + 'test_type': 'disk_utilization', + 'interval': 1, + 'count': 2 + } + } + c = storagecapacity.StorageCapacity(args, self.ctx) + + mock_ssh.SSH().execute.return_value = (0, DISK_UTIL_RAW_OUTPUT, '') + c.run(self.result) + expected_result = json.loads(DISK_UTIL_SAMPLE_OUTPUT) + self.assertEqual(self.result, expected_result) + + def test_capacity_unsuccessful_script_error(self, mock_ssh): + c = storagecapacity.StorageCapacity(self.scn, self.ctx) + + mock_ssh.SSH().execute.return_value = (1, '', 'FOOBAR') + self.assertRaises(RuntimeError, c.run, self.result) + +def main(): + unittest.main() + +if __name__ == '__main__': + main() diff --git a/yardstick/benchmark/scenarios/storage/storagecapacity.bash b/yardstick/benchmark/scenarios/storage/storagecapacity.bash new file mode 100644 index 000000000..6ed4b2811 --- /dev/null +++ b/yardstick/benchmark/scenarios/storage/storagecapacity.bash @@ -0,0 +1,69 @@ +#!/bin/bash + +############################################################################## +# Copyright (c) 2016 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +# Measure storage capacity and scale of a host + +set -e +OUTPUT_FILE=/tmp/storagecapacity-out.log + +# run disk_size test +run_disk_size() +{ + fdisk -l | grep '^Disk.*bytes$' | awk -F [:,\ ] '{print $2,$7}' > $OUTPUT_FILE +} + +# write the disk size to stdout in json format +output_disk_size() +{ + DEVICENUM=`awk 'END{print NR}' $OUTPUT_FILE` + DISKSIZE=`awk 'BEGIN{cnt=0;} {cnt=cnt+$2} END{print cnt}' $OUTPUT_FILE` + echo -e "{\ + \"Number of devices\":\"$DEVICENUM\", \ + \"Total disk size\":\"$DISKSIZE bytes\" \ + }" +} + +# run block_size test +run_block_size() +{ + echo -n "" > $OUTPUT_FILE + blkdevices=`fdisk -l | grep '^Disk.*bytes$' | awk -F [:,\ ] '{print $2}'` + blkdevices=($blkdevices) + for bd in "${blkdevices[@]}";do + blk_size=`blockdev --getbsz $bd` + echo '"'$bd'" '$blk_size >> $OUTPUT_FILE + done +} + +# write the block size to stdout in json format +output_block_size() +{ + BLK_SIZE_STR=`awk 'BEGIN{r="{";} {r=r""$1":"$2","} END{print r}' $OUTPUT_FILE` + BLK_SIZE_STR=${BLK_SIZE_STR%,}"}" + echo $BLK_SIZE_STR +} + +main() +{ + test_type=$1 + case $test_type in + "disk_size" ) + run_disk_size + output_disk_size + ;; + "block_size" ) + run_block_size + output_block_size + ;; + esac +} + +main $1 diff --git a/yardstick/benchmark/scenarios/storage/storagecapacity.py b/yardstick/benchmark/scenarios/storage/storagecapacity.py new file mode 100644 index 000000000..49e3a0339 --- /dev/null +++ b/yardstick/benchmark/scenarios/storage/storagecapacity.py @@ -0,0 +1,133 @@ +############################################################################## +# Copyright (c) 2016 Huawei Technologies Co.,Ltd and other. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +import pkg_resources +import logging +import json + +import yardstick.ssh as ssh +from yardstick.benchmark.scenarios import base + +LOG = logging.getLogger(__name__) + + +class StorageCapacity(base.Scenario): + """Measure storage capacity and scale. + + Parameters: + test_type - specified whether to measure. + valid test type are disk_size, block_size, disk_utilization + type: string + unit: na + default: "disk_size" + interval - specified how ofter to stat disk utilization + type: int + unit: seconds + default: 1 + count - specified how many times to stat disk utilization + type: int + unit: na + default: 15 + + This scenario reads hardware specification, + disk size, block size and disk utilization. + """ + __scenario_type__ = "StorageCapacity" + TARGET_SCRIPT = "storagecapacity.bash" + + def __init__(self, scenario_cfg, context_cfg): + self.scenario_cfg = scenario_cfg + self.context_cfg = context_cfg + self.setup_done = False + + def setup(self): + """scenario setup""" + self.target_script = pkg_resources.resource_filename( + "yardstick.benchmark.scenarios.storage", + StorageCapacity.TARGET_SCRIPT) + host = self.context_cfg['host'] + if host is None: + raise RuntimeError('No right node.Please check the configuration') + host_user = host.get('user', 'ubuntu') + host_ip = host.get('ip', None) + host_pwd = host.get('password', 'root') + LOG.debug("user:%s, host:%s", host_user, host_ip) + + self.client = ssh.SSH(host_user, host_ip, password=host_pwd) + self.client.wait(timeout=600) + + # copy script to host + self.client.run("cat > ~/storagecapacity.sh", + stdin=open(self.target_script, 'rb')) + + self.setup_done = True + + def _get_disk_utilization(self): + """Get disk utilization using iostat.""" + options = self.scenario_cfg["options"] + interval = options.get('interval', 1) + count = options.get('count', 15) + + cmd = "sudo iostat -dx %d %d | awk 'NF==14 && \ + $1 !~ /Device/ {print $1,$14}'" % (interval, count) + + LOG.debug("Executing command: %s", cmd) + status, stdout, stderr = self.client.execute(cmd) + if status: + raise RuntimeError(stderr) + + device_name_arr = [] + min_util_arr = [] + max_util_arr = [] + avg_util_arr = [] + for row in stdout.split('\n'): + kv = row.split(' ') + if len(kv) != 2: + continue + name = kv[0] + util = float(kv[1]) + if name not in device_name_arr: + device_name_arr.append(name) + min_util_arr.append(util) + max_util_arr.append(util) + avg_util_arr.append(util) + else: + i = device_name_arr.index(name) + min_util_arr[i] = min_util_arr[i] \ + if min_util_arr[i] < util else util + max_util_arr[i] = max_util_arr[i] \ + if max_util_arr[i] > util else util + avg_util_arr[i] += util + r = {} + for i in range(len(device_name_arr)): + r[device_name_arr[i]] = {"min_util": min_util_arr[i], + "max_util": max_util_arr[i], + "avg_util": avg_util_arr[i]/count} + return r + + def run(self, result): + """execute the benchmark""" + + if not self.setup_done: + self.setup() + + options = self.scenario_cfg["options"] + test_type = options.get('test_type', 'disk_size') + + if test_type == "disk_utilization": + r = self._get_disk_utilization() + result.update(r) + else: + cmd = "sudo bash storagecapacity.sh " + test_type + + LOG.debug("Executing command: %s", cmd) + status, stdout, stderr = self.client.execute(cmd) + if status: + raise RuntimeError(stderr) + + result.update(json.loads(stdout)) -- cgit 1.2.3-korg