Merge "add k8s capacity test case"
[bottlenecks.git] / testsuites / kubestone / stress_test.py
diff --git a/testsuites/kubestone/stress_test.py b/testsuites/kubestone/stress_test.py
new file mode 100644 (file)
index 0000000..7f5d75f
--- /dev/null
@@ -0,0 +1,156 @@
+from kubernetes import client, config
+from utils.k8s_setup import k8s_utils
+
+import os
+import datetime
+import uuid
+
+import utils.logger as log
+import yaml
+import argparse
+
+LOG = log.Logger(__name__).getLogger()
+
+parser = argparse.ArgumentParser(description='kubestone (k8s stress) tests')
+parser.add_argument("-c", "--TEST_CASE",
+                    help="The path of test case in form of yaml")
+args = parser.parse_args()
+TEST_CASE = args.TEST_CASE
+TEST_CASE_NAME, TEST_CASE_FORMAT = os.path.splitext(
+    os.path.basename(TEST_CASE))
+OUT_FILE = ("/tmp/bottlenecks_kubestone_" +
+            TEST_CASE_NAME + "_" + str(uuid.uuid4()) + ".out")
+
+
+def test_step_result(num, success_num, during_seconds, result):
+    testdata = {}
+    test_result = {}
+    test_result["number_of_deployments"] = float(num)
+    test_result["success_deployments"] = success_num
+    test_result["success_rate"] = success_num / num
+    test_result["duration_time"] = during_seconds
+    test_result["result"] = result
+    testdata["data_body"] = test_result
+    testdata["testcase"] = TEST_CASE_NAME
+    return testdata
+
+
+def main():
+    INSTALLER_TYPE = os.getenv("INSTALLER_TYPE")
+    K8S_CONFIG_PATH = os.getenv("K8S_CONFIG_PATH")
+    K8S_APPS_API_VERSION = os.getenv("K8S_APPS_API_VERSION")
+    K8S_CORE_API_VERSION = os.getenv("K8S_CORE_API_VERSION")
+    # Get k8s config. If provided in the path indicated by
+    # K8S_CONFIG_PATH, only return the path.
+    if K8S_CONFIG_PATH:
+        k8s_utils.get_config_path(
+            K8S_CONFIG_PATH=K8S_CONFIG_PATH)
+    else:
+        if INSTALLER_TYPE:
+            K8S_CONFIG_PATH = k8s_utils.get_config_path(
+                INSTALLER_TYPE=INSTALLER_TYPE)
+        else:
+            k8s_utils.get_config_path()
+
+    config.load_kube_config(K8S_CONFIG_PATH)
+
+    # Initiate api clients
+    if K8S_APPS_API_VERSION:
+        apps_api = k8s_utils.get_apps_api(K8S_APPS_API_VERSION)
+    else:
+        apps_api = k8s_utils.get_apps_api()
+
+    if K8S_CORE_API_VERSION:
+        core_api = k8s_utils.get_core_api(K8S_CORE_API_VERSION)
+    else:
+        core_api = k8s_utils.get_core_api()
+
+    # Read test case in the form of yaml
+    with open(TEST_CASE) as test_case_file:
+        test_case_yaml = yaml.load(test_case_file)
+    if test_case_yaml['template']:
+        if test_case_yaml['template'].lower() == 'none':
+            deployment_yaml = test_case_yaml
+        else:
+            with open(test_case_yaml['template']) as deployment_file:
+                deployment_yaml = yaml.load(deployment_file)
+    else:
+        deployment_yaml = test_case_yaml
+
+    name = deployment_yaml['metadata']['name']
+    namespace = deployment_yaml['namespace']
+    body = client.V1Deployment()
+    body.api_version = deployment_yaml['apiVersion']
+    body.kind = deployment_yaml['kind']
+    body.metadata = deployment_yaml['metadata']
+    body.spec = deployment_yaml['spec']
+    pretty = True
+
+    # Create namespace
+    namespace_existed = k8s_utils.get_namespace_status(namespace)
+    if namespace_existed[0] == 0 and \
+            'exception' not in namespace_existed[1].lower():
+        namespace_read = core_api.read_namespace(namespace, pretty=pretty)
+        LOG.info('Namespace {} already exist: \n{}'.format(
+            namespace, namespace_read))
+    else:
+        namespace_body = client.V1Namespace()
+        namespace_body.metadata = {'name': namespace}
+        namespace_created = core_api.create_namespace(
+            namespace_body, pretty=pretty)
+        LOG.info('Namespace has been created:\n{}'.format(
+            namespace_created))
+
+    # Create deployment
+    deployment_existed = k8s_utils.get_deployment_status(name, namespace)
+    if deployment_existed[0] == 0 and \
+            'exception' not in deployment_existed[1].lower():
+        deployment_read = apps_api.read_namespaced_deployment(
+            name, namespace, pretty=pretty)
+        LOG.info('Deployment {}@{} already exist.'.format(name, namespace))
+        LOG.info('Discription of this deployment is:\n{}'.format(
+            deployment_read))
+    else:
+        deployment_created = apps_api.create_namespaced_deployment(
+            namespace, body, pretty=pretty)
+        LOG.info('Deployment has been created:\n{}'.format(
+            deployment_created))
+
+    # Scale the deployment
+    scaling_steps = deployment_yaml['scaling_steps'].split(',')
+    for step in scaling_steps:
+        start_time = datetime.datetime.now()
+
+        step = int(step)
+        body.spec['replicas'] = step
+        api_response = apps_api.patch_namespaced_deployment_scale(
+            name, namespace, body, pretty=pretty)
+        LOG.info("Deployment replicas is to be scaled to: %s" % step)
+        pods_number = k8s_utils.get_available_pods(name, namespace)
+        while pods_number != step:
+            pods_number = k8s_utils.get_available_pods(name, namespace)
+            LOG.info("Number of available pods are {} out of {}".format(
+                pods_number, step))
+        api_response = apps_api.read_namespaced_deployment_scale(
+            name, namespace, pretty=pretty)
+        LOG.info(
+            "Deployment {}-scaling finished:\n{}".format(
+                step, api_response))
+
+        end_time = datetime.datetime.now()
+        duration_seconds = (start_time - end_time).seconds
+        if pods_number == step:
+            criteria = 'PASS'
+        else:
+            criteria = 'FAIL'
+        test_result_body = test_step_result(
+            step, pods_number, duration_seconds, criteria)
+        k8s_utils.write_json(test_result_body, OUT_FILE)
+    if api_response:
+        LOG.info("Deployment scaling test has been successfuly executed.")
+    LOG.info("Testing results written in: {}".format(OUT_FILE))
+    return
+
+
+if __name__ == '__main__':
+    main()