Add requests templates for performance testing

Add script wich can be used in CLI to generate
'bullets' for yandex-tank, which will be used for
perfomance testing.

Change-Id: I31dea6a8aa490b5f23c5cba6e1ac1c1e5ecd95ad
Implements: blueprint anonymous-statistics-performance-testing
This commit is contained in:
Artem Panchenko 2014-10-23 11:19:15 +03:00
parent 93d5a2986a
commit 874bc3e934
2 changed files with 372 additions and 0 deletions

View File

@ -0,0 +1,158 @@
# Copyright 2014 Mirantis, Inc.
#
# 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 __future__ import print_function
import getopt
import os
import sys
from requests import ActionLogRequestTemplate
from requests import InstallationRequestTemplate
class Settings(object):
def __init__(self):
self.config_file = "ammo.txt"
self.bullets_count = 5
self.bullets_types = ['installation', 'action-log']
self.host_address = '127.0.0.1'
self.max_clusters_count = 10
self.max_cluster_size = 100
self.max_logs_count = 30
def parse_args(argv, settings):
try:
opts, args = getopt.getopt(argv, "ha:c:t:f:", ["help",
"host-address=",
"bullets-count=",
"bullets-type=",
"output-file=",
"max_clusters_count=",
"max_cluster_size=",
"max_logs_count="])
except getopt.GetoptError as err:
print(str(err))
return usage()
for opt, arg in opts:
if opt in ("-h", "--help"):
usage()
elif opt in ("-a", "host-address="):
settings.host_address = arg
elif opt in ("-c", "--bullets-count"):
settings.bullets_count = int(arg)
elif opt in ("-t", "--bullets-type"):
types = []
for type in arg.split(','):
if type in settings.bullets_types:
types.append(type)
else:
usage("ERROR! Unsupported bullet type '{0}'".format(type))
settings.bullets_types = types
elif opt in ("-f", "--output-file"):
settings.config_file = arg
elif opt == "--max_clusters_count":
settings.max_clusters_count = int(arg)
elif opt == "--max_cluster_size":
settings.max_cluster_size = int(arg)
elif opt == "--max_logs_count":
settings.max_logs_count = int(arg)
return settings
def usage(message=None):
usage_text = """
Usage: {name} [OPTIONS]
Example: {name} --bullets-count 10 --bullets-type "installation"
Options:
-a, --host-address set IP address or hostname/domain of
Collector; default - {host}
-c, --bullets-count set number of each bullets type to
generate; default value is {count}
-t, --bullets-type set bullets types; supported types are:
{types}; by default all types are used
-f, --output-file set output file to save bullets;
default file name is "{file}"
-h, --help print this help message
Additional options:
--max_clusters_count set maximum clusters number in each
installation request; default - 10
--max_cluster_size set maximum nodes number assigned to each
environment; default - 100
--max_logs_count set maximum count of action logs which will
in one request; default - 30
""".format(name=sys.argv[0],
host=Settings().host_address,
count=Settings().bullets_count,
types=', '.join(Settings().bullets_types),
file=Settings().config_file)
if message:
print('{0}'.format(message))
print(usage_text)
sys.exit(2)
def save_bullets(bullets, file):
data_to_save = ''
for bullet in bullets:
data_to_save += '\r\n'.join(bullet['headers']) + '\r\n'
data_to_save += '{size} {url}\r\n'.format(size=len(bullet['body']),
url=bullet['url'])
data_to_save += '{body}\r\n\n'.format(body=bullet['body'])
with open(file, 'w+') as _file:
_file.write(data_to_save)
file_size = os.stat(file).st_size / 1024
print("\n\tBullets were saved to '{0}' ({1}K) file\n".format(file,
file_size))
def main(args):
settings = parse_args(args, Settings())
req_template = None
bullets = []
for type in settings.bullets_types:
if type == "installation":
req_template = InstallationRequestTemplate(
max_clusters_count=settings.max_clusters_count,
max_cluster_size=settings.max_cluster_size)
elif type == "action-log":
req_template = ActionLogRequestTemplate(
max_logs_count=settings.max_logs_count)
for _ in xrange(settings.bullets_count):
bullet_url = req_template.url
bullet_headers = ['[Host: {0}]'.format(settings.host_address)]
bullet_headers.extend(req_template.headers)
bullet_body = req_template.get_request_body()
bullet = {
'url': bullet_url,
'headers': bullet_headers,
'body': bullet_body
}
bullets.append(bullet)
save_bullets(bullets, settings.config_file)
if __name__ == '__main__':
main(sys.argv[1:])

View File

@ -0,0 +1,214 @@
# Copyright 2014 Mirantis, Inc.
#
# 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.
import datetime
import json
import random
class BaseRequestTemplate(object):
def __init__(self):
self.headers = [
'[Content-Type: application/json]',
'[Connection: close]',
'[User-Agent: Tank]'
]
self.fuel_releases = {
'6.0': [
{
'version': '2014.2-6.0',
'os': 'Ubuntu',
'name': 'Juno on Ubuntu 12.04.04'
},
{
'version': '2014.2-6.0',
'os': 'CentOS',
'name': 'Juno on CentOS 6.5'
}
],
'6.0.1': [
{
'version': '2014.2-6.0.1',
'os': 'Ubuntu',
'name': 'Juno on Ubuntu 12.04.05'
},
{
'version': '2014.2-6.0.1',
'os': 'CentOS',
'name': 'Juno on CentOS 6.6'
}
]
}
self.cluster_statuses = ['new',
'operational',
'error']
self.nodes_roles = ['controller',
'compute',
'mongodb',
'ceph-osd',
'cinder',
'zabbix']
self.nodes_statuses = ['ready',
'discovered',
'provisioned',
'provisioning',
'deploying',
'deployed',
'error']
self.api_versions = ['v1', 'v2']
self.feature_groups = ['mirantis', 'experimental']
@property
def random_sha(self):
return ''.join(random.choice('abcdef0123456789') for _ in xrange(40))
@property
def fuel_release(self):
return {
"ostf_sha": self.random_sha,
"nailgun_sha": self.random_sha,
"astute_sha": self.random_sha,
"fuellib_sha": self.random_sha,
"api": random.choice(self.api_versions),
"release": random.choice(self.fuel_releases.keys()),
"feature_groups": random.sample(
self.feature_groups,
random.randint(1, len(self.feature_groups)))
}
class InstallationRequestTemplate(BaseRequestTemplate):
def __init__(self, max_clusters_count=10, max_cluster_size=100):
BaseRequestTemplate.__init__(self)
self.max_clusters_count = max_clusters_count
self.max_cluster_size = max_cluster_size
self.url = "/api/v1/installation_structure/"
@property
def clusters_number(self):
return random.randint(1, self.max_clusters_count)
@property
def nodes_number(self):
return random.randint(1, self.max_cluster_size)
def get_request_body(self):
release = self.fuel_release
clusters_number = self.clusters_number
allocated_nodes = 0
unallocated_nodes = self.nodes_number
clusters = []
for cluster_id in xrange(1, clusters_number):
nodes = []
nodes_number = self.nodes_number
allocated_nodes += nodes_number
for node_id in xrange(1, nodes_number):
node = {
'status': random.choice(self.nodes_statuses),
'id': node_id,
'roles': random.sample(
self.nodes_roles,
random.randint(1, len(self.nodes_roles)))
}
nodes.append(node)
controllers = [n for n in nodes if 'controller' in n['roles']]
cluster = {
'release': random.choice(
self.fuel_releases.get(release["release"])),
'nodes': nodes,
'id': cluster_id,
'mode': 'ha_full' if len(controllers) > 1 else 'multinode',
'nodes_num': len(nodes),
'status': random.choice(self.cluster_statuses),
'attributes': {},
}
clusters.append(cluster)
data = {
"installation_structure": {
"master_node_uid": self.random_sha,
"clusters_num": clusters_number,
"allocated_nodes_num": allocated_nodes,
"unallocated_nodes_num": unallocated_nodes,
"fuel_release": release,
"clusters": clusters
}
}
return json.dumps(data)
class ActionLogRequestTemplate(BaseRequestTemplate):
def __init__(self, max_logs_count=30):
BaseRequestTemplate.__init__(self)
self.max_logs_count = max_logs_count
self.url = "/api/v1/action_logs/"
self.actions = {
'action_group-1': {
"type": "nailgun_task",
"name": "action_name-1"
},
'action_group-2': {
"type": "nailgun_task",
"name": "action_name-2"
},
'action_group-3': {
"type": "http_request",
"name": "action_name-3"
},
'action_group-4': {
"type": "http_request",
"name": "action_name-4"
}
}
def get_request_body(self):
actor_id = random.randint(1, 999)
master_node_uid = self.random_sha
data = {'action_logs': []}
for id in xrange(0, self.max_logs_count):
action_group = random.choice(self.actions.keys())
action_log = {
'master_node_uid': master_node_uid,
'external_id': random.randint(1, 999999),
'body': {
"id": id,
"actor_id": str(actor_id),
"action_group": action_group,
"action_name": self.actions[action_group]['name'],
"action_type": self.actions[action_group]['type'],
"start_timestamp": str(datetime.datetime.now()),
"end_timestamp": str(datetime.datetime.now()),
"additional_info": {},
"is_sent": False,
"cluster_id": random.randint(1, 999),
"task_uuid": self.random_sha
}
}
data['action_logs'].append(action_log)
return json.dumps(data)