add k8s capacity test case
[bottlenecks.git] / testsuites / kubestone / stress_test.py
1 from kubernetes import client, config
2 from utils.k8s_setup import k8s_utils
3
4 import os
5 import datetime
6 import uuid
7
8 import utils.logger as log
9 import yaml
10 import argparse
11
12 LOG = log.Logger(__name__).getLogger()
13
14 parser = argparse.ArgumentParser(description='kubestone (k8s stress) tests')
15 parser.add_argument("-c", "--TEST_CASE",
16                     help="The path of test case in form of yaml")
17 args = parser.parse_args()
18 TEST_CASE = args.TEST_CASE
19 TEST_CASE_NAME, TEST_CASE_FORMAT = os.path.splitext(
20     os.path.basename(TEST_CASE))
21 OUT_FILE = ("/tmp/bottlenecks_kubestone_" +
22             TEST_CASE_NAME + "_" + str(uuid.uuid4()) + ".out")
23
24
25 def test_step_result(num, success_num, during_seconds, result):
26     testdata = {}
27     test_result = {}
28     test_result["number_of_deployments"] = float(num)
29     test_result["success_deployments"] = success_num
30     test_result["success_rate"] = success_num / num
31     test_result["duration_time"] = during_seconds
32     test_result["result"] = result
33     testdata["data_body"] = test_result
34     testdata["testcase"] = TEST_CASE_NAME
35     return testdata
36
37
38 def main():
39     INSTALLER_TYPE = os.getenv("INSTALLER_TYPE")
40     K8S_CONFIG_PATH = os.getenv("K8S_CONFIG_PATH")
41     K8S_APPS_API_VERSION = os.getenv("K8S_APPS_API_VERSION")
42     K8S_CORE_API_VERSION = os.getenv("K8S_CORE_API_VERSION")
43     # Get k8s config. If provided in the path indicated by
44     # K8S_CONFIG_PATH, only return the path.
45     if K8S_CONFIG_PATH:
46         k8s_utils.get_config_path(
47             K8S_CONFIG_PATH=K8S_CONFIG_PATH)
48     else:
49         if INSTALLER_TYPE:
50             K8S_CONFIG_PATH = k8s_utils.get_config_path(
51                 INSTALLER_TYPE=INSTALLER_TYPE)
52         else:
53             k8s_utils.get_config_path()
54
55     config.load_kube_config(K8S_CONFIG_PATH)
56
57     # Initiate api clients
58     if K8S_APPS_API_VERSION:
59         apps_api = k8s_utils.get_apps_api(K8S_APPS_API_VERSION)
60     else:
61         apps_api = k8s_utils.get_apps_api()
62
63     if K8S_CORE_API_VERSION:
64         core_api = k8s_utils.get_core_api(K8S_CORE_API_VERSION)
65     else:
66         core_api = k8s_utils.get_core_api()
67
68     # Read test case in the form of yaml
69     with open(TEST_CASE) as test_case_file:
70         test_case_yaml = yaml.load(test_case_file)
71     if test_case_yaml['template']:
72         if test_case_yaml['template'].lower() == 'none':
73             deployment_yaml = test_case_yaml
74         else:
75             with open(test_case_yaml['template']) as deployment_file:
76                 deployment_yaml = yaml.load(deployment_file)
77     else:
78         deployment_yaml = test_case_yaml
79
80     name = deployment_yaml['metadata']['name']
81     namespace = deployment_yaml['namespace']
82     body = client.V1Deployment()
83     body.api_version = deployment_yaml['apiVersion']
84     body.kind = deployment_yaml['kind']
85     body.metadata = deployment_yaml['metadata']
86     body.spec = deployment_yaml['spec']
87     pretty = True
88
89     # Create namespace
90     namespace_existed = k8s_utils.get_namespace_status(namespace)
91     if namespace_existed[0] == 0 and \
92             'exception' not in namespace_existed[1].lower():
93         namespace_read = core_api.read_namespace(namespace, pretty=pretty)
94         LOG.info('Namespace {} already exist: \n{}'.format(
95             namespace, namespace_read))
96     else:
97         namespace_body = client.V1Namespace()
98         namespace_body.metadata = {'name': namespace}
99         namespace_created = core_api.create_namespace(
100             namespace_body, pretty=pretty)
101         LOG.info('Namespace has been created:\n{}'.format(
102             namespace_created))
103
104     # Create deployment
105     deployment_existed = k8s_utils.get_deployment_status(name, namespace)
106     if deployment_existed[0] == 0 and \
107             'exception' not in deployment_existed[1].lower():
108         deployment_read = apps_api.read_namespaced_deployment(
109             name, namespace, pretty=pretty)
110         LOG.info('Deployment {}@{} already exist.'.format(name, namespace))
111         LOG.info('Discription of this deployment is:\n{}'.format(
112             deployment_read))
113     else:
114         deployment_created = apps_api.create_namespaced_deployment(
115             namespace, body, pretty=pretty)
116         LOG.info('Deployment has been created:\n{}'.format(
117             deployment_created))
118
119     # Scale the deployment
120     scaling_steps = deployment_yaml['scaling_steps'].split(',')
121     for step in scaling_steps:
122         start_time = datetime.datetime.now()
123
124         step = int(step)
125         body.spec['replicas'] = step
126         api_response = apps_api.patch_namespaced_deployment_scale(
127             name, namespace, body, pretty=pretty)
128         LOG.info("Deployment replicas is to be scaled to: %s" % step)
129         pods_number = k8s_utils.get_available_pods(name, namespace)
130         while pods_number != step:
131             pods_number = k8s_utils.get_available_pods(name, namespace)
132             LOG.info("Number of available pods are {} out of {}".format(
133                 pods_number, step))
134         api_response = apps_api.read_namespaced_deployment_scale(
135             name, namespace, pretty=pretty)
136         LOG.info(
137             "Deployment {}-scaling finished:\n{}".format(
138                 step, api_response))
139
140         end_time = datetime.datetime.now()
141         duration_seconds = (start_time - end_time).seconds
142         if pods_number == step:
143             criteria = 'PASS'
144         else:
145             criteria = 'FAIL'
146         test_result_body = test_step_result(
147             step, pods_number, duration_seconds, criteria)
148         k8s_utils.write_json(test_result_body, OUT_FILE)
149     if api_response:
150         LOG.info("Deployment scaling test has been successfuly executed.")
151     LOG.info("Testing results written in: {}".format(OUT_FILE))
152     return
153
154
155 if __name__ == '__main__':
156     main()