--- /dev/null
+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()
##############################################################################
import os
+import commands
+import json
import utils.logger as log
from kubernetes import client, watch
LOG = log.Logger(__name__).getLogger()
INSTALLER_TYPE = os.getenv("INSTALLER_TYPE")
+K8S_UTILS = "/home/opnfv/bottlenecks/utils/k8s_setup"
-def get_config_path(INSTALLER_TYPE=None, CONFIG_PATH="/tmp/k8s_config"):
+def get_config_path(INSTALLER_TYPE=None, K8S_CONFIG_PATH="/tmp/k8s_config"):
if INSTALLER_TYPE:
- CMD = "bash k8s_config_pre.sh -i " + INSTALLER_TYPE + \
- " -c " + CONFIG_PATH
+ CMD = "bash " + K8S_UTILS + "/k8s_config_pre.sh -i " \
+ + INSTALLER_TYPE + \
+ " -c " + K8S_CONFIG_PATH
LOG.info("Executing command: " + CMD)
- CONFIG_PATH = os.popen(CMD)
+ os.popen(CMD)
else:
- if not os.path.exists(CONFIG_PATH):
+ if not os.path.exists(K8S_CONFIG_PATH):
raise Exception("Must at least specify the path \
of k8s config!")
- return CONFIG_PATH
+ return K8S_CONFIG_PATH
def get_core_api(version='v1'):
API = client.CoreV1Api()
LOG.info(API)
else:
- raise Exception("Must input a validate verison!")
+ raise Exception("Must input a valid verison!")
return API
+def get_apps_api(version='v1'):
+ if version.lower() == 'v1':
+ API = client.AppsV1Api()
+ LOG.info(API)
+ else:
+ raise Exception("Must input a valid verison!")
+ return API
+
+
+def get_namespace_status(namespace):
+ CMD = ("kubectl get ns | grep %s" % namespace)
+ namespace_existed = commands.getstatusoutput(CMD)
+ return namespace_existed
+
+
+def get_deployment_status(name, namespace):
+ CMD = ("kubectl get deployment --namespace={} | grep {}".format(
+ namespace, name))
+ deployment_existed = commands.getstatusoutput(CMD)
+ return deployment_existed
+
+
+def get_available_pods(name, namespace):
+ CMD = ("kubectl get deployment --namespace={} | grep {}".format(
+ namespace, name) + " | awk '{print $5}'")
+ available_pods = commands.getstatusoutput(CMD)
+ return int(available_pods[1])
+
+
def watch_namespace(namespace, count=3, stop=None, request_timeout=0):
w = watch.Watch()
LOG.debug("Watch object generated: {}".format(w))
if not count:
LOG.info("Ended.\n")
w.stop()
+
+
+def write_json(data, file_name):
+ with open(file_name, "a") as f:
+ f.write(json.dumps(data, f))
+ f.write("\n")