From b99b94a8522ac70b92f0d5d768e2e3d23bae6901 Mon Sep 17 00:00:00 2001 From: Mark Vanderwiel Date: Mon, 16 Mar 2015 17:03:16 -0500 Subject: [PATCH] New test_patch helper script This tool allows a single patch to be tested against the chef repo. It will to do job of cloning the repo, merging in the patch(s), setting up the test and running it, basic queries and tempest. Also enhanced the Berksfile to allow for easy local development. Usage: chef exec ruby test_patch.rb help test Change-Id: I32ba57c29f2f5caee0391ea791ffe10fe06caceb --- Berksfile | 6 +- README.md | 5 ++ doc/tools.md | 25 ++++++ tools/test_patch.rb | 188 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 doc/tools.md create mode 100644 tools/test_patch.rb diff --git a/Berksfile b/Berksfile index 0cd826f..8f58353 100644 --- a/Berksfile +++ b/Berksfile @@ -4,7 +4,11 @@ source 'https://supermarket.chef.io' dashboard database data-processing identity image integration-test network object-storage ops-database ops-messaging orchestration telemetry}.each do |cookbook| - cookbook "openstack-#{cookbook}", github: "stackforge/cookbook-openstack-#{cookbook}", branch: 'master' + if ENV['REPO_DEV'] && Dir.exist?("../cookbook-openstack-#{cookbook}") + cookbook "openstack-#{cookbook}", path: "../cookbook-openstack-#{cookbook}" + else + cookbook "openstack-#{cookbook}", github: "stackforge/cookbook-openstack-#{cookbook}", branch: 'master' + end end cookbook "openstack_client", github: "stackforge/cookbook-openstack-client", branch: 'master' diff --git a/README.md b/README.md index dbbde8a..888e8eb 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,7 @@ $ sudo su - ```bash # Access the controller as noted above $ source openrc +$ nova-manage version $ nova service-list && nova hypervisor-list $ glance image-list $ keystone user-list @@ -161,6 +162,10 @@ To cleanup everything, use the following rake command. $ chef exec rake clean ``` +## Tools + +See the doc/tools.md for more information. + ## Databags Some basic information about the use of databags within this repo. diff --git a/doc/tools.md b/doc/tools.md new file mode 100644 index 0000000..46a58b1 --- /dev/null +++ b/doc/tools.md @@ -0,0 +1,25 @@ +# Tools + +## Using the test_patch tool + +The tools/test_patch.rb tool will do most of the heavy lifting of testing out one or more patches. +It will basically create a clean environment with a copy of the repo and the patched cookbook, and then run +one of the test environments. + +To see the various options and help: + +```shell +$ chef exec ruby tools\test_patch.rb help test +``` + +## Cookbook Patch Development + +The Berksfile in this repo has been enhanced to look for local working cookbook development directories and use them +to when running the test suite. Simply set REPO_DEV=True and create a directory tree as follows: + +* base_dev_dir\ +** openstack-chef-repo +** cookbook-openstack-*** + +When doing the 'chef exec rake berks_vendor', the Berks file will pick up cookbooks changes from the +cookbook-openstack-*** directories. diff --git a/tools/test_patch.rb b/tools/test_patch.rb new file mode 100644 index 0000000..914b572 --- /dev/null +++ b/tools/test_patch.rb @@ -0,0 +1,188 @@ +# Test Patches +# +# Test patches against the testing repo +# +# Author: Mark Vanderwiel () +# Copyright (c) 2015, IBM, Corp. + +require 'fileutils' +require 'English' +require 'chef/mixin/shell_out' +require 'open3' +require 'thor' + +def version + '0.1.0' +end + +# rubocop:disable LineLength + +def run(command, verbose = true) # rubocop:disable Metrics/MethodLength + puts "## Running command: [#{Dir.pwd}] $ #{command}" + live_stream = STDOUT + live_stream = nil unless verbose + runner = Mixlib::ShellOut.new(command, live_stream: live_stream, timeout: 1800).run_command + runner.error! + runner.stdout +end + +def check_dependencies + puts '## Checking dependencies' + run('chef --version') + run('vagrant --version') +end + +def get_gerrit_user(user) + return user unless user.to_s.empty? + puts '## Using git config to find gitreview.username' + git_config = run('git config -l', false) + /^gitreview.username=(?.*)$/i =~ git_config + abort 'Error! Gerrit user could not be found, please use --username' if user.to_s.empty? + user +end + +def get_patch_info(user, patch) # rubocop:disable Metrics/MethodLength + puts "## Gathering information for patch: #{patch} with user: #{user}" + patch_info = run("ssh -p 29418 #{user}@review.openstack.org gerrit query --current-patch-set #{patch}", false) + /^\s*project: stackforge\/(?.*)$/i =~ patch_info + /^\s*ref: (?.*)$/i =~ patch_info + abort "Error! Patch: #{patch} not valid" if patch_project.nil? + patch_cookbook = patch_project.gsub('cookbook-', '') + puts "## Patch project: #{patch_project}" + puts "## Patch cookbook: #{patch_cookbook}" + puts "## Patch ref: #{patch_ref}" + abort "Error! Only cookbook-openstack-* patches allowed, not from project: #{patch_project}" unless patch_project[/cookbook-openstack-.*/] + { patch: patch, project: patch_project, cookbook: patch_cookbook, ref: patch_ref } +end + +def add_patch(patch_info) + puts "## Adding patch: #{patch_info[:patch]} to cookbook: #{patch_info[:cookbook]}" + run("git clone git@github.com:stackforge/#{patch_info[:project]}.git") + Dir.chdir(patch_info[:project]) do + run("git fetch https://review.openstack.org/stackforge/#{patch_info[:project]} #{patch_info[:ref]}") + run('git checkout FETCH_HEAD') + end +end + +def run_tempest + puts '## Starting tempest tests' + Dir.chdir('vms') do + run("vagrant ssh -c \"sudo bash -c 'cd /opt/tempest && ./run_tests.sh -V'\" controller") + end +end + +def run_basic_queries # rubocop:disable Metrics/MethodLength + puts '## Starting basic query tests' + { + 'nova-manage' => ['version', 'db version'], + 'nova' => %w(--version service-list hypervisor-list net-list image-list), + 'glance-manage' => %w(db_version), + 'glance' => %w(--version image-list), + 'keystone-manage' => %w(db_version), + 'keystone' => %w(--version user-list endpoint-list role-list service-list tenant-list), + 'cinder-manage' => ['version list', 'db version'], + 'cinder' => %w(--version list), + 'rabbitmqctl' => %w(cluster_status) + }.each do |cli, commands| + commands.each do |command| + Dir.chdir('vms') do + run("vagrant ssh -c \"sudo bash -c 'source /root/openrc && #{cli} #{command}'\" controller") + end + end + end + puts '## Finished basic query tests' +end + +def get_test_dir(env, os, patches) + patch = 'master' + patch = patches.gsub(' ', '-') unless patches.to_s.empty? + dir_name = "test-#{env}-#{os}-#{patch}" + puts "## Repo dir: #{dir_name}" + dir_name +end + +# Class to run the CLI +class MyCLI < Thor + desc 'test', 'Spin up test repo with optional patches' + long_desc <<-LONGDESC + This will run the test suite. There are options to include one or more patches using the gerrit review number. + The test will run in a new directory called test---, where aio_nova is the default environment, + ubuntu14 is the default os platform and master (no patches) is the default for patch. + + For patches, the tool will try to find your gerrit review name using the "git config -l". If the tool + cannot automatically find your gerrit review name, use the -u option to specify it.\n + + Examples: + + "$ chef exec ruby test_patch test"\n + This will run the aio_nova against the master branch. + + "$ chef exec ruby test_patch test -t"\n + This will run the aio_nova against the master branch and run the tempest suite. + + "$ chef exec ruby test_patch test -p 161495 -u kramvan"\n + This will run the aio_nova against the master branch including the 161495 patch set. + + "$ chef exec ruby test_patch test -p 161495,123456 -u kramvan"\n + This will run the aio_nova against the master branch including patches 161495 and 123456. + + "$ chef exec ruby test_patch test -p 161495 -i"\n + This will run the aio_nova against the master branch including the 161495 patch set and + run the converge a second time to help check for idempotentcy. Also, in this case the + gerrit username was automatically found. + + "$ chef exec ruby test_patch test -k -s"\n + This is a developer run. The -s will skip the setup steps and just run the converge and tests + again. This allows a developer to tweak and debug a node and then try converge again. + +LONGDESC + option :patches, aliases: :p, default: nil, banner: ' Gerrit patch numbers: xxx,zzz, defaults to no patches just use master branch.' + option :env, aliases: :e, default: 'aio_nova', banner: ' Test environment to run.' + option :os, aliases: :o, default: 'ubuntu14', banner: ' OS to use, ubuntu14 or centos7.' + option :idempotent, aliases: :i, default: false, type: :boolean, banner: ' Run converge a second time to help check for idempotentcy.' + option :query, aliases: :q, default: true, type: :boolean, banner: ' Run basic test queries after converge completes.' + option :tempest, aliases: :t, default: false, type: :boolean, banner: ' Run Tempest suite.' + option :keep, aliases: :k, default: false, type: :boolean, banner: ' Keep the environment, do not run \"rake destroy_machines\".' + option :username, aliases: :u, banner: ' Gerrit user name used to fetch a patch if tool cannot automatically find it in git config.' + option :skip, aliases: :s, banner: ' Skip all source changes, just run converge and tests again. For development after manually tweaking a node.' + def test # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, CyclomaticComplexity, Metrics/PerceivedComplexity + puts "## Starting repo test version: #{version} environment: #{options[:env]} on os: #{options[:os]}" + ENV['REPO_OS'] = options[:os] + + # TODO: Allow more flexibility with dependencies + check_dependencies + + dir_name = get_test_dir(options[:env], options[:os], options[:patches]) + Dir.mkdir(dir_name) unless Dir.exist?(dir_name) + Dir.chdir(dir_name) do + if options[:patches] && !options[:skip] + user = get_gerrit_user(options[:username]) + options[:patches].split(' ').each do |patch| + patch_info = get_patch_info(user, patch) + add_patch(patch_info) + end + end + + run('git clone git@github.com:stackforge/openstack-chef-repo.git') unless options[:skip] + Dir.chdir('openstack-chef-repo') do + ENV['REPO_DEV'] = options[:patches] + run('chef exec rake berks_vendor') unless options[:skip] + + (1..(options[:idempotent] ? 2 : 1)).each do |pass| + puts "## Starting Converge pass: #{pass}" + run("chef exec rake #{options[:env]}") + run_basic_queries if options[:query] + run_tempest if options[:tempest] + puts "## Finished Converge pass: #{pass}" + end + + run('chef exec rake destroy_machines') unless options[:keep] + end + end + + FileUtils.rm_rf(dir_name) unless options[:keep] + puts "## Finished repo test version: #{version} environment: #{options[:env]} on os: #{options[:os]}" + end +end + +MyCLI.start(ARGV)