| package com.mirantis.mcp |
| |
| /** |
| * |
| * Tests providing functions |
| * |
| */ |
| |
| /** |
| * Configure docker image with tests |
| * |
| * @param dockerImageLink Docker image link with rally and tempest |
| * @param target Host to run tests |
| * @param output_dir Directory for results |
| * @param ext_variables The set of external variables |
| */ |
| def runContainerConfiguration(master, dockerImageLink, target, output_dir, ext_variables){ |
| def salt = new com.mirantis.mk.Salt() |
| def common = new com.mirantis.mk.Common() |
| def output_file = 'docker.log' |
| def nodes = getNodeList(master) |
| def nodes_hw = getNodeList(master, 'G@virtual:physical') |
| def _pillar = salt.getPillar(master, 'I@keystone:server', 'keystone:server') |
| def keystone = _pillar['return'][0].values()[0] |
| def ssh_key = getFileContent(master, 'I@salt:master', '/root/.ssh/id_rsa') |
| salt.cmdRun(master, target, "docker run -tid --net=host --name=qa_tools " + |
| " ${ext_variables} " + |
| "-e tempest_version=15.0.0 -e OS_USERNAME=${keystone.admin_name} " + |
| "-e OS_PASSWORD=${keystone.admin_password} -e OS_TENANT_NAME=${keystone.admin_tenant} " + |
| "-e OS_AUTH_URL=http://${keystone.bind.private_address}:${keystone.bind.private_port}/v2.0 " + |
| "-e OS_REGION_NAME=${keystone.region} -e OS_ENDPOINT_TYPE=admin ${dockerImageLink} /bin/bash") |
| salt.cmdRun(master, target, "docker exec qa_tools bash -c \"sudo mkdir -p /root/.ssh; " + |
| "echo \'${ssh_key}\' | sudo tee /root/.ssh/id_rsa > /dev/null; " + |
| "sudo chmod 700 /root/.ssh; sudo chmod 600 /root/.ssh/id_rsa; " + |
| "echo -e '${nodes}' > nodes.json; echo -e '${nodes_hw}' > nodes_hw.json\"") |
| salt.cmdRun(master, target, "docker exec qa_tools bash -c /opt/devops-qa-tools/deployment/configure.sh > ${output_file}") |
| def file_content = getFileContent(master, target, output_file) |
| writeFile file: "${output_dir}${output_file}", text: file_content |
| } |
| |
| /** |
| * Get file content (encoded). The content encoded by Base64. |
| * |
| * @param target Compound target (should target only one host) |
| * @param file File path to read |
| * @return The encoded content of the file |
| */ |
| def getFileContentEncoded(master, target, file) { |
| def salt = new com.mirantis.mk.Salt() |
| def file_content = '' |
| def cmd = "base64 -w0 ${file} > ${file}_encoded; " + |
| "split -b 1MB -d ${file}_encoded ${file}__; " + |
| "rm ${file}_encoded" |
| salt.cmdRun(master, target, cmd, false, null, false) |
| def filename = file.tokenize('/').last() |
| def folder = file - filename |
| def parts = salt.runSaltProcessStep(master, target, 'file.find', ["${folder}", "type=f", "name=${filename}__*"]) |
| for ( part in parts['return'][0].values()[0]) { |
| def _result = salt.cmdRun(master, target, "cat ${part}", false, null, false) |
| file_content = file_content + _result['return'][0].values()[0].replaceAll('Salt command execution success','') |
| } |
| salt.runSaltProcessStep(master, target, 'file.find', ["${folder}", "type=f", "name=${filename}__*", "delete"]) |
| return file_content |
| } |
| |
| /** |
| * Copy files from remote to local directory. The content of files will be |
| * decoded by Base64. |
| * |
| * @param target Compound target (should target only one host) |
| * @param folder The path to remote folder. |
| * @param output_dir The path to local folder. |
| */ |
| def addFiles(master, target, folder, output_dir) { |
| def salt = new com.mirantis.mk.Salt() |
| def _result = salt.runSaltProcessStep(master, target, 'file.find', ["${folder}", "type=f"]) |
| def files = _result['return'][0].values()[0] |
| for (file in files) { |
| def file_content = getFileContentEncoded(master, target, "${file}") |
| def fileName = file.tokenize('/').last() |
| writeFile file: "${output_dir}${fileName}_encoded", text: file_content |
| def cmd = "base64 -d ${output_dir}${fileName}_encoded > ${output_dir}${fileName}; " + |
| "rm ${output_dir}${fileName}_encoded" |
| sh(script: cmd) |
| } |
| } |
| |
| /** |
| * Get reclass value |
| * |
| * @param target The host for which the values will be provided |
| * @param filter Parameters divided by dots |
| * @return The pillar data |
| */ |
| def getReclassValue(master, target, filter) { |
| def common = new com.mirantis.mk.Common() |
| def salt = new com.mirantis.mk.Salt() |
| def items = filter.tokenize('.') |
| def _result = salt.cmdRun(master, 'I@salt:master', "reclass-salt -o json -p ${target}", false, null, false) |
| _result = common.parseJSON(_result['return'][0].values()[0]) |
| for (int k = 0; k < items.size(); k++) { |
| if ( _result ) { |
| _result = _result["${items[k]}"] |
| } |
| } |
| return _result |
| } |
| |
| /** |
| * Create list of nodes in JSON format. |
| * |
| * @param filter The Salt's matcher |
| * @return JSON list of nodes |
| */ |
| def getNodeList(master, filter = null) { |
| def salt = new com.mirantis.mk.Salt() |
| def common = new com.mirantis.mk.Common() |
| def nodes = [] |
| def filtered_list = null |
| def controllers = salt.getMinions(master, 'I@nova:controller') |
| def hw_nodes = salt.getMinions(master, 'G@virtual:physical') |
| if ( filter ) { |
| filtered_list = salt.getMinions(master, filter) |
| } |
| def _result = salt.cmdRun(master, 'I@salt:master', "reclass-salt -o json -t", false, null, false) |
| def reclass_top = common.parseJSON(_result['return'][0].values()[0]) |
| def nodesList = reclass_top['base'].keySet() |
| for (int i = 0; i < nodesList.size(); i++) { |
| if ( filtered_list ) { |
| if ( ! filtered_list.contains(nodesList[i]) ) { |
| continue |
| } |
| } |
| def ip = getReclassValue(master, nodesList[i], '_param.linux_single_interface.address') |
| def network_data = [ip: ip, name: 'management'] |
| def roles = [nodesList[i].tokenize('.')[0]] |
| if ( controllers.contains(nodesList[i]) ) { |
| roles.add('controller') |
| } |
| if ( hw_nodes.contains(nodesList[i]) ) { |
| roles.add('hw_node') |
| } |
| nodes.add([id: i+1, ip: ip, roles: roles, network_data: [network_data]]) |
| } |
| return common.prettify(nodes) |
| } |
| |
| /** |
| * Execute mcp sanity tests |
| * |
| * @param salt_url Salt master url |
| * @param salt_credentials Salt credentials |
| * @param test_set Test set for mcp sanity framework |
| * @param output_dir Directory for results |
| */ |
| def runSanityTests(salt_url, salt_credentials, test_set, output_dir) { |
| def common = new com.mirantis.mk.Common() |
| creds = common.getCredentials(salt_credentials) |
| username = creds.username |
| password = creds.password |
| def script = ". ${env.WORKSPACE}/venv/bin/activate; pytest --junitxml ${output_dir}cvp_sanity.xml -sv ${env.WORKSPACE}/cvp-sanity-checks/cvp_checks/tests/${test_set}" |
| withEnv(["SALT_USERNAME=${username}", "SALT_PASSWORD=${password}", "SALT_URL=${salt_url}"]) { |
| def statusCode = sh script:script, returnStatus:true |
| } |
| } |
| |
| /** |
| * Execute tempest tests |
| * |
| * @param target Host to run tests |
| * @param dockerImageLink Docker image link |
| * @param pattern If not false, will run only tests matched the pattern |
| * @param output_dir Directory for results |
| */ |
| def runTempestTests(master, target, dockerImageLink, output_dir, pattern = "false") { |
| def salt = new com.mirantis.mk.Salt() |
| def output_file = 'docker-tempest.log' |
| def results = '/root/qa_results' |
| def dest_folder = '/home/rally/qa_results' |
| salt.runSaltProcessStep(master, target, 'file.remove', ["${results}"]) |
| salt.runSaltProcessStep(master, target, 'file.mkdir', ["${results}", "mode=777"]) |
| def _pillar = salt.getPillar(master, 'I@keystone:server', 'keystone:server') |
| def keystone = _pillar['return'][0].values()[0] |
| def env_vars = ['tempest_version=15.0.0', |
| "OS_USERNAME=${keystone.admin_name}", |
| "OS_PASSWORD=${keystone.admin_password}", |
| "OS_TENANT_NAME=${keystone.admin_tenant}", |
| "OS_AUTH_URL=http://${keystone.bind.private_address}:${keystone.bind.private_port}/v2.0", |
| "OS_REGION_NAME=${keystone.region}", |
| 'OS_ENDPOINT_TYPE=admin'].join(' -e ') |
| def cmd = '/opt/devops-qa-tools/deployment/configure.sh; ' |
| if (pattern == 'false') { |
| cmd += 'rally verify start --pattern set=full --detailed; ' |
| } |
| else { |
| cmd += "rally verify start --pattern set=${pattern} --detailed; " |
| } |
| cmd += "rally verify report --type json --to ${dest_folder}/report-tempest.json; " + |
| "rally verify report --type html --to ${dest_folder}/report-tempest.html" |
| salt.cmdRun(master, target, "docker run -i --rm --net=host -e ${env_vars} " + |
| "-v ${results}:${dest_folder} ${dockerImageLink} " + |
| "/bin/bash -c \"${cmd}\" > ${results}/${output_file}") |
| addFiles(master, target, results, output_dir) |
| } |
| |
| /** |
| * Execute rally tests |
| * |
| * @param target Host to run tests |
| * @param dockerImageLink Docker image link |
| * @param pattern If not false, will run only tests matched the pattern |
| * @param output_dir Directory for results |
| * @param ext_variables The list of external variables |
| */ |
| def runRallyTests(master, target, dockerImageLink, output_dir, ext_variables = []) { |
| def salt = new com.mirantis.mk.Salt() |
| def output_file = 'docker-rally.log' |
| def results = '/root/qa_results' |
| def dest_folder = '/home/rally/qa_results' |
| salt.runSaltProcessStep(master, target, 'file.remove', ["${results}"]) |
| salt.runSaltProcessStep(master, target, 'file.mkdir', ["${results}", "mode=777"]) |
| def _pillar = salt.getPillar(master, 'I@keystone:server', 'keystone:server') |
| def keystone = _pillar['return'][0].values()[0] |
| def env_vars = ( ['tempest_version=15.0.0', |
| "OS_USERNAME=${keystone.admin_name}", |
| "OS_PASSWORD=${keystone.admin_password}", |
| "OS_TENANT_NAME=${keystone.admin_tenant}", |
| "OS_AUTH_URL=http://${keystone.bind.private_address}:${keystone.bind.private_port}/v2.0", |
| "OS_REGION_NAME=${keystone.region}", |
| 'OS_ENDPOINT_TYPE=admin'] + ext_variables ).join(' -e ') |
| def cmd = '/opt/devops-qa-tools/deployment/configure.sh; ' + |
| 'rally task start combined_scenario.yaml ' + |
| "--task-args-file /opt/devops-qa-tools/rally-scenarios/task_arguments.yaml; " + |
| "rally task export --type junit-xml --to ${dest_folder}/report-rally.xml; " + |
| "rally task report --out ${dest_folder}/report-rally.html" |
| salt.cmdRun(master, target, "docker run -i --rm --net=host -e ${env_vars} " + |
| "-v ${results}:${dest_folder} ${dockerImageLink} " + |
| "/bin/bash -c \"${cmd}\" > ${results}/${output_file}") |
| addFiles(master, target, results, output_dir) |
| } |
| |
| /** |
| * Generate test report |
| * |
| * @param target Host to run script from |
| * @param dockerImageLink Docker image link |
| * @param output_dir Directory for results |
| */ |
| def generateTestReport(master, target, dockerImageLink, output_dir) { |
| def report_file = 'jenkins_test_report.html' |
| def salt = new com.mirantis.mk.Salt() |
| def common = new com.mirantis.mk.Common() |
| def results = '/root/qa_results' |
| def dest_folder = '/opt/devops-qa-tools/generate_test_report/test_results' |
| salt.runSaltProcessStep(master, target, 'file.remove', ["${results}"]) |
| salt.runSaltProcessStep(master, target, 'file.mkdir', ["${results}", "mode=777"]) |
| def reports = ['report-tempest.json', |
| 'report-rally.xml', |
| 'report-k8s-e2e-tests.txt', |
| 'report-ha.json', |
| 'report-spt.txt'] |
| for ( report in reports ) { |
| if ( fileExists("${output_dir}${report}") ) { |
| common.infoMsg("Copying ${report} to docker container") |
| def items = sh(script: "base64 -w0 ${output_dir}${report} > ${output_dir}${report}_encoded; " + |
| "split -b 100KB -d -a 4 ${output_dir}${report}_encoded ${output_dir}${report}__; " + |
| "rm ${output_dir}${report}_encoded; " + |
| "find ${output_dir} -type f -name ${report}__* -printf \'%f\\n\' | sort", returnStdout: true) |
| for ( item in items.tokenize() ) { |
| def content = sh(script: "cat ${output_dir}${item}", returnStdout: true) |
| salt.cmdRun(master, target, "echo \"${content}\" >> ${results}/${report}_encoded", false, null, false) |
| sh(script: "rm ${output_dir}${item}") |
| } |
| salt.cmdRun(master, target, "base64 -d ${results}/${report}_encoded > ${results}/${report}; " + |
| "rm ${results}/${report}_encoded", false, null, false) |
| } |
| } |
| |
| def cmd = "jenkins_report.py --path /opt/devops-qa-tools/generate_test_report/; " + |
| "cp ${report_file} ${dest_folder}/${report_file}" |
| salt.cmdRun(master, target, "docker run -i --rm --net=host " + |
| "-v ${results}:${dest_folder} ${dockerImageLink} " + |
| "/bin/bash -c \"${cmd}\"") |
| def report_content = salt.getFileContent(master, target, "${results}/${report_file}") |
| writeFile file: "${output_dir}${report_file}", text: report_content |
| } |
| |
| /** |
| * Execute SPT tests |
| * |
| * @param target Host to run tests |
| * @param dockerImageLink Docker image link |
| * @param output_dir Directory for results |
| * @param ext_variables The list of external variables |
| */ |
| def runSptTests(master, target, dockerImageLink, output_dir, ext_variables = []) { |
| def salt = new com.mirantis.mk.Salt() |
| def results = '/root/qa_results' |
| def dest_folder = '/home/rally/qa_results' |
| salt.runSaltProcessStep(master, target, 'file.remove', ["${results}"]) |
| salt.runSaltProcessStep(master, target, 'file.mkdir', ["${results}", "mode=777"]) |
| def nodes = getNodeList(master) |
| def nodes_hw = getNodeList(master, 'G@virtual:physical') |
| def _pillar = salt.getPillar(master, 'I@keystone:server', 'keystone:server') |
| def keystone = _pillar['return'][0].values()[0] |
| def ssh_key = salt.getFileContent(master, 'I@salt:master', '/root/.ssh/id_rsa') |
| def env_vars = ( ['tempest_version=15.0.0', |
| "OS_USERNAME=${keystone.admin_name}", |
| "OS_PASSWORD=${keystone.admin_password}", |
| "OS_TENANT_NAME=${keystone.admin_tenant}", |
| "OS_AUTH_URL=http://${keystone.bind.private_address}:${keystone.bind.private_port}/v2.0", |
| "OS_REGION_NAME=${keystone.region}", |
| 'OS_ENDPOINT_TYPE=admin'] + ext_variables ).join(' -e ') |
| salt.runSaltProcessStep(master, target, 'file.write', ["${results}/nodes.json", nodes]) |
| salt.runSaltProcessStep(master, target, 'file.write', ["${results}/nodes_hw.json", nodes_hw]) |
| def cmd = '/opt/devops-qa-tools/deployment/configure.sh; ' + |
| 'sudo mkdir -p /root/.ssh; sudo chmod 700 /root/.ssh; ' + |
| "echo \\\"${ssh_key}\\\" | sudo tee /root/.ssh/id_rsa > /dev/null; " + |
| 'sudo chmod 600 /root/.ssh/id_rsa; ' + |
| "sudo timmy -c simplified-performance-testing/config.yaml " + |
| "--nodes-json ${dest_folder}/nodes.json --log-file ${dest_folder}/docker-spt2.log; " + |
| "./simplified-performance-testing/SPT_parser.sh > ${dest_folder}/report-spt.txt; " + |
| "custom_spt_parser.sh ${dest_folder}/nodes_hw.json > ${dest_folder}/report-spt-hw.txt; " + |
| "cp /tmp/timmy/archives/general.tar.gz ${dest_folder}/results-spt.tar.gz" |
| salt.cmdRun(master, target, "docker run -i --rm --net=host -e ${env_vars} " + |
| "-v ${results}:${dest_folder} ${dockerImageLink} /bin/bash -c " + |
| "\"${cmd}\" > ${results}/docker-spt.log") |
| addFiles(master, target, results, output_dir) |
| } |
| |
| /** |
| * Cleanup |
| * |
| * @param target Host to run commands |
| */ |
| def runCleanup(master, target) { |
| def salt = new com.mirantis.mk.Salt() |
| if ( salt.cmdRun(master, target, "docker ps -f name=qa_tools -q", false, null, false)['return'][0].values()[0] ) { |
| salt.cmdRun(master, target, "docker rm -f qa_tools") |
| } |
| } |
| |
| /** |
| * Prepare venv for any python project |
| * Note: <repo_name>\/requirements.txt content will be used |
| * for this venv |
| * |
| * @param repo_url Repository url to clone |
| * @param proxy Proxy address to use |
| */ |
| def prepareVenv(repo_url, proxy) { |
| def python = new com.mirantis.mk.Python() |
| repo_name = "${repo_url}".tokenize("/").last() |
| sh "rm -rf ${repo_name}" |
| withEnv(["HTTPS_PROXY=${proxy}", "HTTP_PROXY=${proxy}", "https_proxy=${proxy}", "http_proxy=${proxy}"]) { |
| sh "git clone ${repo_url}" |
| python.setupVirtualenv("${env.WORKSPACE}/venv", "python2", [], "${env.WORKSPACE}/${repo_name}/requirements.txt", true) |
| } |
| } |
| |
| /** Install docker if needed |
| * |
| * @param target Target node to install docker pkg |
| */ |
| def installDocker(master, target) { |
| def salt = new com.mirantis.mk.Salt() |
| if ( ! salt.runSaltProcessStep(master, target, 'pkg.version', ["docker-engine"]) ) { |
| salt.runSaltProcessStep(master, target, 'pkg.install', ["docker.io"]) |
| } |
| } |