From 65268b6594921834cf7ef38df86f172c8c0b2b05 Mon Sep 17 00:00:00 2001 From: Praveen Kumar Date: Fri, 21 Sep 2018 18:48:49 +0530 Subject: [PATCH] Issue #6 add ci for fedora iso --- Vagrantfile | 11 +- centos_ci.sh | 218 ++++++++++++++++++------ tests/test.py | 127 -------------- tests/test.sh | 155 +++++++++++++++++ tests/utils/minishift_latest_version.py | 8 +- 5 files changed, 332 insertions(+), 187 deletions(-) delete mode 100644 tests/test.py create mode 100644 tests/test.sh diff --git a/Vagrantfile b/Vagrantfile index 75456c6..d6dfd50 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -2,7 +2,7 @@ # vi: set ft=ruby : Vagrant.configure(2) do |config| - config.vm.box = "fedora/28" + config.vm.box = "generic/fedora28" config.vm.provider "virtualbox" do |v, override| v.memory = 2048 @@ -23,11 +23,14 @@ Vagrant.configure(2) do |config| target_path = ENV['USERPROFILE'].gsub(/\\/,'/').gsub(/[[:alpha:]]{1}:/){|s|'/' + s.downcase.sub(':', '')} config.vm.synced_folder ENV['USERPROFILE'], target_path, type: 'sshfs', sshfs_opts_append: '-o umask=000 -o uid=1000 -o gid=1000' else - config.vm.synced_folder ENV['HOME'], ENV['HOME'], type: 'sshfs', sshfs_opts_append: '-o umask=000 -o uid=1000 -o gid=1000' + config.vm.synced_folder "/opt/fedora", "/opt", type: 'sshfs', sshfs_opts_append: '-o umask=000 -o uid=1000 -o gid=1000' end config.vm.provision "shell", inline: <<-SHELL - # Docker and parted is required to get selinux context: https://bugzilla.redhat.com/show_bug.cgi?id=1303565 - sudo dnf install -y git livecd-tools docker parted + # Docker and parted packages are required to get selinux context: https://bugzilla.redhat.com/show_bug.cgi?id=1303565 + sudo dnf -y update + sudo dnf install -y git livecd-tools docker parted make sudo gettext + cd /opt/ + make SHELL end diff --git a/centos_ci.sh b/centos_ci.sh index 2f61ac4..a40b937 100755 --- a/centos_ci.sh +++ b/centos_ci.sh @@ -6,62 +6,172 @@ set -x # Exit on error set -e +# GitHub user +REPO_OWNER="minishift" +REPO_NAME="minishift-centos-iso" + +######################################################## +# Exit with message on failure of last executed command +# Arguments: +# $1 - Exit code of last executed command +# $2 - Error message +######################################################## +function exit_on_failure() { + if [[ "$1" != 0 ]]; then + echo "$2" + exit 1 + fi +} + # Source environment variables of the jenkins slave # that might interest this worker. -if [ -e "jenkins-env" ]; then - cat jenkins-env \ - | grep -E "(JENKINS_URL|GIT_BRANCH|GIT_COMMIT|BUILD_NUMBER|ghprbSourceBranch|ghprbActualCommit|BUILD_URL|ghprbPullId|CICO_API_KEY)=" \ - | sed 's/^/export /g' \ - > ~/.jenkins-env - source ~/.jenkins-env -fi +function load_jenkins_vars() { + if [ -e "jenkins-env" ]; then + cat jenkins-env \ + | grep -E "(JENKINS_URL|GIT_BRANCH|GIT_COMMIT|BUILD_NUMBER|ghprbSourceBranch|ghprbActualCommit|BUILD_URL|ghprbPullId|CICO_API_KEY|GITHUB_TOKEN|JOB_NAME|RELEASE_VERSION)=" \ + | sed 's/^/export /g' \ + > ~/.jenkins-env + source ~/.jenkins-env + fi + + echo 'CICO: Jenkins ENVs loaded' +} + +function install_required_packages() { + # Install EPEL repo + yum -y install epel-release + # Get all the deps in + yum -y install make \ + git \ + curl \ + kvm \ + qemu-kvm \ + libvirt \ + python-requests \ + libvirt-devel \ + git \ + jq \ + gcc \ + https://releases.hashicorp.com/vagrant/2.0.2/vagrant_2.0.2_x86_64.rpm + + echo 'CICO: Required packages installed' +} + +function create_required_files() { + mkdir -p /opt/fedora + cp -r * /opt/fedora + cd /opt/fedora +} + +function start_libvirt() { + systemctl start libvirtd +} + +function install_vagrant_plugin() { + vagrant plugin install vagrant-libvirt + vagrant plugin install vagrant-sshfs +} + +function vagrant_up_and_destroy() { + vagrant up + vagrant destroy -f || true +} + +function setup_kvm_machine_driver() { + curl -L https://github.com/dhiltgen/docker-machine-kvm/releases/download/v0.10.0/docker-machine-driver-kvm-centos7 > /usr/local/bin/docker-machine-driver-kvm && \ + chmod +x /usr/local/bin/docker-machine-driver-kvm +} + +function perform_artifacts_upload() { + rm -rf build/bin # Don't upload bin folder + set +x + + # For PR build, GIT_BRANCH is set to branch name other than origin/master + if [[ "$GIT_BRANCH" = "origin/master" ]]; then + # http://stackoverflow.com/a/22908437/1120530; Using --relative as --rsync-path not working + mkdir -p minishift-centos-iso/master/$BUILD_NUMBER/ + cp build/* minishift-centos-iso/master/$BUILD_NUMBER/ + RSYNC_PASSWORD=$1 rsync -a --relative minishift-centos-iso/master/$BUILD_NUMBER/ minishift@artifacts.ci.centos.org::minishift/ + echo "Find Artifacts here http://artifacts.ci.centos.org/${REPO_OWNER}/${REPO_NAME}/master/$BUILD_NUMBER ." + else + # http://stackoverflow.com/a/22908437/1120530; Using --relative as --rsync-path not working + mkdir -p minishift-centos-iso/pr/$ghprbPullId/ + cp build/* minishift-centos-iso/pr/$ghprbPullId/ + RSYNC_PASSWORD=$1 rsync -a --relative minishift-centos-iso/pr/$ghprbPullId/ minishift@artifacts.ci.centos.org::minishift/ + echo "Find Artifacts here http://artifacts.ci.centos.org/${REPO_OWNER}/${REPO_NAME}/pr/$ghprbPullId ." + fi +} + +function create_release_commit() { + # Create master branch as git clone in CI doesn't create it + git checkout -b master + # Bump version and commit + sed -i "s|VERSION=.*|VERSION=$RELEASE_VERSION|" Makefile + git add Makefile + git commit -m "cut v$RELEASE_VERSION" + git push https://$REPO_OWNER:$GITHUB_TOKEN@github.com/$REPO_OWNER/$REPO_NAME master +} + +function add_release_notes() { + release_id=$(curl -s "https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/releases" | jq --arg release "v$RELEASE_VERSION" -r ' .[] | if .name == $release then .id else empty end') + + if [[ "$release_id" != "" ]]; then + MILESTONE_ID=`curl -s https://api.github.com/repos/minishift/${REPO_NAME}/milestones?state=all | jq --arg version "v$RELEASE_VERSION" -r ' .[] | if .title == $version then .number else empty end'` + + if [[ "$MILESTONE_ID" != "" ]]; then + # Generate required json payload for release note + ./scripts/release/issue-list.sh -r $REPO_NAME -m $MILESTONE_ID | jq -Rn 'inputs + "\n"' | jq -s '{body: add }' > json_payload.json + # Add release notes + curl -H "Content-Type: application/json" -H "Authorization: token $GITHUB_TOKEN" \ + --data @json_payload.json https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/releases/$release_id + + echo "Release notes of Minishift CentOS ISO v$RELEASE_VERSION has been successfully updated. Find the release notes here https://github.com/${REPO_OWNER}/${REPO_NAME}/releases/tag/v$RELEASE_VERSION." + else + echo "Failed to get milestone ID for Minishift CentOS ISO v$RELEASE_VERSION. Use manual approach to update the release notes here https://github.com/${REPO_OWNER}/${REPO_NAME}/releases/tag/v$RELEASE_VERSION." + fi + else + return 1 + fi +} + +function perform_release() { + create_release_commit + exit_on_failure "$?" "Unable to create release commit." + + make release + exit_on_failure "$?" "Failed to release Minishift CentOS ISO v$RELEASE_VERSION. Try to release manually." + echo "Minishift CentOS ISO v$RELEASE_VERSION has been successfully released. Find the latest release here https://github.com/$REPO_OWNER/$REPO_NAME/releases/tag/v$RELEASE_VERSION." + + add_release_notes; + exit_on_failure "$?" "Failed to update release notes of Minishift CentOS ISO v$RELEASE_VERSION. Try to manually update the release notes here - https://github.com/$REPO_OWNER/$REPO_NAME/releases/tag/v$RELEASE_VERSION." +} + +# Execution starts here +load_jenkins_vars +install_required_packages +create_required_files +start_libvirt +install_vagrant_plugin +vagrant_up_and_destroy +setup_kvm_machine_driver + +# Set Terminal +export TERM=xterm-256color +# Add git a/c identity +git config --global user.email "29732253+minishift-bot@users.noreply.github.com" +git config --global user.name "Minishift Bot" + +# Build ISO and test +make test + +# Retrieve password for rsync +CICO_PASS=$(echo $CICO_API_KEY | cut -d'-' -f1-2) +# Export GITHUB_ACCESS_TOKEN to prevent Github rate limit and push to master during release job +export GITHUB_ACCESS_TOKEN=$GITHUB_TOKEN -# Get all the deps in -yum -y install \ - make \ - git \ - epel-release \ - livecd-tools \ - curl \ - docker \ - parted \ - kvm \ - qemu-kvm \ - libvirt - -# Start Libvirt -sudo systemctl start libvirtd - -# Install Avocado -sudo curl https://repos-avocadoproject.rhcloud.com/static/avocado-el.repo -o /etc/yum.repos.d/avocado.repo -sudo yum install -y avocado - -# Setup test drivers -curl -L https://github.com/dhiltgen/docker-machine-kvm/releases/download/v0.7.0/docker-machine-driver-kvm > /usr/local/bin/docker-machine-driver-kvm && \ -chmod +x /usr/local/bin/docker-machine-driver-kvm - -# Prepare ISO for testing -make centos_iso - -# Let's test with showing log enabled -SHOW_LOG=--show-job-log make test - -# On reaching successfully at this point, upload artifacts -PASS=$(echo $CICO_API_KEY | cut -d'-' -f1-2) - -rm -rf build/bin # Don't upload bin folder -set +x -# For PR build, GIT_BRANCH is set to branch name other than origin/master -if [[ "$GIT_BRANCH" = "origin/master" ]]; then - # http://stackoverflow.com/a/22908437/1120530; Using --relative as --rsync-path not working - mkdir -p minishift-centos-iso/master/$BUILD_NUMBER/ - cp build/* minishift-centos-iso/master/$BUILD_NUMBER/ - RSYNC_PASSWORD=$PASS rsync -a --relative minishift-centos-iso/master/$BUILD_NUMBER/ minishift@artifacts.ci.centos.org::minishift/ - echo "Find Artifacts here http://artifacts.ci.centos.org/minishift/minishift-centos-iso/master/$BUILD_NUMBER ." +if [[ "$JOB_NAME" = "minishift-centos-iso-release" ]]; then + perform_release else - # http://stackoverflow.com/a/22908437/1120530; Using --relative as --rsync-path not working - mkdir -p minishift-centos-iso/pr/$ghprbPullId/ - cp build/* minishift-centos-iso/pr/$ghprbPullId/ - RSYNC_PASSWORD=$PASS rsync -a --relative minishift-centos-iso/pr/$ghprbPullId/ minishift@artifacts.ci.centos.org::minishift/ - echo "Find Artifacts here http://artifacts.ci.centos.org/minishift/minishift-centos-iso/pr/$ghprbPullId ." + # Runs for both PR and master jobs + perform_artifacts_upload $CICO_PASS fi diff --git a/tests/test.py b/tests/test.py deleted file mode 100644 index ad335d7..0000000 --- a/tests/test.py +++ /dev/null @@ -1,127 +0,0 @@ -import glob -import os -import re -import subprocess -import sys -import time -import shutil -import socket - -from avocado import VERSION -from avocado import Test - -class MinishiftISOTest(Test): - - def setUp(self): - ''' Test Setup ''' - self.log.info("################################################################") - self.log.info("Avocado version : %s" % VERSION) - self.log.info("################################################################") - - self.repo_dir = os.path.dirname(os.path.realpath(__file__)) + "/.." - self.scripts_dir = self.repo_dir + "/tests/" - self.bin_dir = self.repo_dir + "/build/bin/" - self.driver_name = 'kvm' - self.iso_name = 'minishift-centos7' - - # Find iso files and skip test if no ISO file is found - self.iso_file = self.repo_dir + "/build/%s.iso" % self.iso_name - if not os.path.isfile(self.iso_file): - self.skip("Skipping testing as no ISO found in 'build' directory.") - - def test_boot_vm_out_of_iso(self): - ''' Test booting up VM out of ISO ''' - start_args = (self.driver_name, "file://" + self.iso_file) - cmd = self.bin_dir + "minishift start --vm-driver %s --iso-url %s" % start_args - self.execute_test({ 'cmd': cmd }) - - def test_ssh_connection_to_vm(self): - ''' Test SSH connection to the VM ''' - cmd = self.bin_dir + "minishift ssh exit" - self.execute_test({ 'cmd': cmd }) - - def test_ip_of_vm(self): - ''' Test IP of the VM ''' - cmd = self.bin_dir + "minishift ip" - output = self.execute_test({ 'cmd': cmd }) - - # Verify IP - try: - socket.inet_aton(output) - except socket.error: - self.fail("Error in getting IP with minishift VM.") - - def test_docker_env_evaluable(self): - cmd = self.bin_dir + "minishift docker-env" - output = self.execute_test({ 'cmd': cmd }) - self.check_data_evaluable(output.rstrip()) - - def test_cifs_installed(self): - cmd = self.bin_dir + "minishift ssh 'sudo /sbin/mount.cifs -V'" - output = self.execute_test({ 'cmd': cmd }) - self.assertEqual(output.rstrip(), 'mount.cifs version: 6.2') - - def test_sshfs_installed(self): - cmd = self.bin_dir + "minishift ssh 'sudo sshfs -V'" - output = self.execute_test({ 'cmd': cmd }) - self.assertRegexpMatches(output.rstrip(), r'.*SSHFS version 2\.5.*') - - def test_nfs_installed(self): - cmd = self.bin_dir + "minishift ssh 'sudo /sbin/mount.nfs -V'" - output = self.execute_test({ 'cmd': cmd }) - self.assertEqual(output.rstrip(), 'mount.nfs: (linux nfs-utils 1.3.0)') - - def test_stopping_vm(self): - ''' Test stopping machine ''' - cmd = self.bin_dir + "minishift stop" - self.execute_test({ 'cmd': cmd }) - - # Check VM status status - cmd = self.bin_dir + "minishift status" - self.log.info("Executing command : %s" % cmd) - process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) - output = process.communicate()[0] - self.assertEqual(0, process.returncode) - self.assertEqual('Stopped', output.rstrip()) - - def test_swapspace(self): - ''' Test if swap space is available on restart ''' - start_args = (self.driver_name, "file://" + self.iso_file) - cmd = self.bin_dir + "minishift start --vm-driver %s --iso-url %s" % start_args - self.execute_test({ 'cmd': cmd }) - - # Check swap space - cmd = self.bin_dir + "minishift ssh \"echo `free | tail -n 1 | awk '{print $2}'`\"" - self.log.info("Executing command : %s" % cmd) - output = self.execute_test({ 'cmd': cmd }) - self.assertNotEqual(0, output) - - def test_delete_vm(self): - ''' Test removing machine ''' - cmd = self.bin_dir + "minishift delete" - self.execute_test({ 'cmd': cmd }) - - # Check VM status status - cmd = self.bin_dir + "minishift status" - self.log.info("Executing command : %s" % cmd) - process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) - output = process.communicate()[0] - self.assertEqual(0, process.returncode) - self.assertEqual('Does Not Exist', output.rstrip()) - - # Helper Functions - def execute_test(self, options): - cmd = options['cmd'] - self.log.info("\n*******\nExecuting command : %s\n*******" % cmd) - process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) - output, error_message = process.communicate() - if error_message: - self.log.debug("Error: %s" % error_message) - - self.assertEqual(0, process.returncode) - return output - - def check_data_evaluable(self, data): - for line in data.splitlines(): - REGEX = re.compile('^#.*|^export [a-zA-Z_]+=.*|^\n') - self.assertTrue(REGEX.match(line)) diff --git a/tests/test.sh b/tests/test.sh new file mode 100644 index 0000000..0b8c6e8 --- /dev/null +++ b/tests/test.sh @@ -0,0 +1,155 @@ +#!/bin/sh + +BINARY=build/bin/minishift +ISO=file://$(pwd)/build/minishift-fedora.iso +EXTRA_FLAGS="--show-libmachine-logs" +RHEL_IMAGE="registry.access.redhat.com/rhel7/rhel-atomic" + +function print_success_message() { + echo "" + echo " ------------ [ $1 - Passed ]" + echo "" +} + +function exit_with_message() { + if [[ "$1" != 0 ]]; then + echo "$2" + exit 1 + fi +} + +function assert_equal() { + if [ "$1" != "$2" ]; then + echo "Expected '$2' but got '$1'" + exit 1 + fi +} + +# http://www.linuxjournal.com/content/validating-ip-address-bash-script +function assert_valid_ip() { + local ip=$1 + local valid=1 + + if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then + OIFS=$IFS + IFS='.' + ip=($ip) + IFS=$OIFS + [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \ + && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]] + valid=$? + fi + + if [[ "$valid" != 0 ]]; then + echo "IP '$1' is invalid" + exit 1 + fi + } + +function verify_start_instance() { + $BINARY start --iso-url $ISO $EXTRA_FLAGS + exit_with_message "$?" "Error starting Minishift VM" + output=`$BINARY status | sed -n 1p` + assert_equal "$output" "Minishift: Running" + print_success_message "Starting VM" +} + +function verify_stop_instance() { + $BINARY stop + exit_with_message "$?" "Error starting Minishift VM" + output=`$BINARY status | sed -n 1p` + assert_equal "$output" "Minishift: Stopped" + print_success_message "Stopping VM" +} + +function verify_swap_space() { + output=`$BINARY ssh -- free | tail -n 1 | awk '{print $2}'` + if [ "$output" == "0" ]; then + echo "Expected non zero but got '$output'" + exit 1 + fi + print_success_message "Swap space check" +} + +function verify_ssh_connection() { + output=`$BINARY ssh -- echo hello` + assert_equal "$output" "hello" + print_success_message "SSH Connection" +} + +function verify_vm_ip() { + output=`$BINARY ip` + assert_valid_ip $output + print_success_message "Getting VM IP" +} + +function verify_cifs_installation() { + expected="mount.cifs version: 6.8" + output=`$BINARY ssh -- sudo /sbin/mount.cifs -V` + assert_equal "$output" "$expected" + print_success_message "CIFS installation" +} + +function verify_sshfs_installation() { + expected="SSHFS version 2.10" + output=`$BINARY ssh -- sudo sshfs -V` + echo $output | grep "$expected" > /dev/null + if [ "$?" != "0" ]; then + echo "Expected exit status of command '$BINARY ssh -- sudo sshfs -V' to be 0." + exit 1 + fi + print_success_message "SSHFS installation" +} + +function verify_nfs_installation() { + expected="mount.nfs: (linux nfs-utils 2.3.2)" + output=`$BINARY ssh -- sudo /sbin/mount.nfs -V /need/for/version` + assert_equal "$output" "$expected" + print_success_message "NFS installation" +} + +function verify_bind_mount() { + output=`$BINARY ssh -- 'findmnt | grep "\[/var/lib/" | wc -l'` + assert_equal $output "8" + print_success_message "Bind mount check" +} + +function verify_hvkvp_installation() { + expected="Error opening pool" + output=`$BINARY ssh -- 'hvkvp'` + assert_equal "$output" "$expected" + print_success_message "HVKVP check" +} + +function verify_xfs_mount() { + expected="ftype=1" + output=`$BINARY ssh -- xfs_info /mnt/sda1 | grep ftype | awk '{print $6}'` + assert_equal "$output" "$expected" + print_success_message "xfs mount successful" +} + +function verify_rhel_registry_pull() { + $BINARY ssh -- docker pull $RHEL_IMAGE + exit_with_message "$?" "Error starting Minishift VM" +} + +function verify_delete() { + $BINARY delete --force + exit_with_message "$?" "Error deleting Minishift VM" +} + +# Tests +verify_start_instance +sleep 90 +verify_stop_instance +verify_start_instance +verify_swap_space +verify_vm_ip +verify_cifs_installation +verify_sshfs_installation +verify_nfs_installation +verify_bind_mount +verify_xfs_mount +verify_rhel_registry_pull +verify_delete + diff --git a/tests/utils/minishift_latest_version.py b/tests/utils/minishift_latest_version.py index bd4a643..446fc2e 100644 --- a/tests/utils/minishift_latest_version.py +++ b/tests/utils/minishift_latest_version.py @@ -3,11 +3,15 @@ import requests import re import os +import platform -OS = os.getenv('OS', 'linux') +distributionInfo = platform.platform() + +matchObj = re.match( r'linux|darwin', distributionInfo, re.I) +OS= matchObj.group().lower() def main(): - pattern = re.compile(".*%s-amd64.(tgz|zip)$" % OS) + pattern = re.compile(".*%s-amd64.tgz$" % OS) r = requests.get('https://api.github.com/repos/minishift/minishift/releases/latest') for asset in r.json()['assets']: if pattern.match(asset['name']):