kloudbuster/kloudbuster/kb_runner_http.py

159 lines
7.1 KiB
Python

# Copyright 2015 Cisco Systems, Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from kloudbuster.kb_runner_base import KBException
from kloudbuster.kb_runner_base import KBRunner
import kloudbuster.log as logging
LOG = logging.getLogger(__name__)
class KBSetStaticRouteException(KBException):
pass
class KBHTTPServerUpException(KBException):
pass
class KBHTTPBenchException(KBException):
pass
class KBRunner_HTTP(KBRunner):
"""
Control the testing VMs on the testing cloud
"""
def __init__(self, client_list, config, single_cloud=True):
KBRunner.__init__(self, client_list, config, single_cloud)
def header_formatter(self, stage, vm_count):
conns = vm_count * self.config.http_tool_configs.connections
rate_limit = vm_count * self.config.http_tool_configs.rate_limit
msg = "Stage %d: %d VM(s), %d Connections, %d Expected RPS" %\
(stage, vm_count, conns, rate_limit)
return msg
def setup_static_route(self, active_range, timeout=30):
func = {'cmd': 'setup_static_route', 'active_range': active_range}
self.send_cmd('EXEC', 'http', func)
cnt_succ = self.polling_vms(timeout)[0]
if cnt_succ != len(self.client_dict):
raise KBSetStaticRouteException()
def check_http_service(self, active_range, timeout=30):
func = {'cmd': 'check_http_service', 'active_range': active_range}
self.send_cmd('EXEC', 'http', func)
cnt_succ = self.polling_vms(timeout)[0]
if cnt_succ != len(self.client_dict):
raise KBHTTPServerUpException()
def run_http_test(self, active_range):
func = {'cmd': 'run_http_test', 'active_range': active_range,
'parameter': dict(self.config.http_tool_configs)}
self.send_cmd('EXEC', 'http', func)
# Give additional 30 seconds for everybody to report results
timeout = self.config.http_tool_configs.duration + 30
cnt_pending = self.polling_vms(timeout)[2]
if cnt_pending != 0:
LOG.warning("Testing VMs are not returning results within grace period, "
"summary shown below may not be accurate!")
# Parse the results from HTTP benchmarking tool
for key, instance in self.client_dict.items():
self.result[key] = instance.perf_client_parser(**self.result[key])
def single_run(self, active_range=None, http_test_only=False):
try:
if not http_test_only:
if self.single_cloud:
LOG.info("Setting up static route to reach tested cloud...")
self.setup_static_route(active_range)
LOG.info("Waiting for HTTP service to come up...")
self.check_http_service(active_range)
if self.config.prompt_before_run:
_ = input("Press enter to start running benchmarking tools...")
LOG.info("Running HTTP Benchmarking...")
self.report = {'seq': 0, 'report': None}
self.result = {}
self.run_http_test(active_range)
# Call the method in corresponding tools to consolidate results
perf_tool = list(self.client_dict.values())[0].perf_tool
results = list(self.result.values())
LOG.kbdebug(results)
self.tool_result = perf_tool.consolidate_results(results)
self.tool_result['http_rate_limit'] =\
len(self.client_dict) * self.config.http_tool_configs.rate_limit
self.tool_result['total_connections'] =\
len(self.client_dict) * self.config.http_tool_configs.connections
vm_count = active_range[1] - active_range[0] + 1\
if active_range else len(self.full_client_dict)
self.tool_result['total_client_vms'] = vm_count
self.tool_result['total_server_vms'] = self.tool_result['total_client_vms']
# self.tool_result['host_stats'] = self.gen_host_stats()
except KBSetStaticRouteException:
raise KBException("Could not set static route.")
except KBHTTPServerUpException:
raise KBException("HTTP service is not up in testing cloud.")
except KBHTTPBenchException:
raise KBException("Error while running HTTP benchmarking tool.")
def run(self, test_only=False, run_label=None):
if self.config.progression.enabled:
self.tool_result = {}
start = self.config.progression.vm_start
multiple = self.config.progression.vm_multiple
limit = self.config.progression.http_stop_limit
timeout = self.config.http_tool_configs.timeout
vm_list = self.get_sorted_vm_list()
self.client_dict = {}
cur_stage = 1
while True:
cur_vm_count = len(self.client_dict)
if start == 1:
target_vm_count = 1 if cur_stage == 1 else (cur_stage - 1) * multiple
else:
target_vm_count = cur_stage * multiple
timeout_at_percentile = 0
if target_vm_count > len(self.full_client_dict):
break
if self.tool_result and 'latency_stats' in self.tool_result:
err = self.tool_result['http_sock_err'] + self.tool_result['http_sock_timeout']
pert_dict = dict(self.tool_result['latency_stats'])
if limit[1] in pert_dict:
timeout_at_percentile = pert_dict[limit[1]] // 1000000
elif limit[1] != 0:
LOG.warning('Percentile %s%% is not a standard statistic point.' % limit[1])
if err > limit[0] or timeout_at_percentile > timeout:
LOG.warning('KloudBuster is stopping the iteration because the result '
'reaches the stop limit.')
break
for idx in range(cur_vm_count, target_vm_count):
self.client_dict[vm_list[idx]] = self.full_client_dict[vm_list[idx]]
description = "-- %s --" % self.header_formatter(cur_stage, len(self.client_dict))
LOG.info(description)
self.single_run(active_range=[0, target_vm_count - 1],
http_test_only=test_only)
LOG.info('-- Stage %s: %s --' % (cur_stage, str(self.tool_result)))
self.tool_result['description'] = description
cur_stage += 1
yield self.tool_result
else:
self.single_run(http_test_only=test_only)
yield self.tool_result