Skip to content
This repository was archived by the owner on May 12, 2021. It is now read-only.
310 changes: 287 additions & 23 deletions .ci/test-install-docs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,238 @@

set -e

# The go binary isn't installed, but we checkout the repos to the standard
# golang locations.
export GOPATH=${GOPATH:-${HOME}/go}

typeset -r script_name="${0##*/}"
typeset -r script_dir="$(cd "$(dirname "${0}")" && pwd)"

typeset -r docker_image="busybox"
typeset -r kata_project_url="github.com/kata-containers"
typeset -r test_repo="${kata_project_url}/tests"
typeset -r test_repo_url="https://${test_repo}"
typeset -r test_repo_dir="${GOPATH}/src/${test_repo}"
typeset -r kata_project_dir="${GOPATH}/src/${kata_project_url}"

typeset -r mgr="${test_repo_dir}/cmd/kata-manager/kata-manager.sh"
typeset -r doc_to_script="${test_repo_dir}/.ci/kata-doc-to-script.sh"

die()
{
local msg="$*"
echo >&2 "ERROR: $msg"
exit 1
}

info()
{
msg="$*"
local msg="$*"
echo "INFO: $msg"
}

# Detect if any installation documents changed. If so, run the
# kata manager to "execute" the install guide to ensure the
# commands it specified result in a working system.
check_install_guides()
usage()
{
cat <<EOT
Description: Run Kata documentation CI tests.

Usage: $script_name [options]

Options:

-h : Show this help.
-t <dir> : Run all scripts ("\*.sh" files) in the specified
directory.

Notes:
- The '-t' option is not generally useful - it is used by this
script which re-exec's itself with this option.

EOT
}

# Re-execute the running script from a temporary directory to allow the
# script to continue executing even if the original source file is deleted.
reexec_in_tmpdir()
{
local -r test_dir="$1"

[ -d "${test_dir}" ] || die "invalid test dir: ${test_dir}"

if [ "${script_dir}" = "${test_dir}" ]
then
# Already running from temp directory so nothing else to do
return
fi

local new
new="${test_dir}/${script_name}"

install --mode 750 "${0}" "${new}"

info "Re-execing ${0} as ${new}"

cd "${test_dir}"

exec "${new}" -t "${test_dir}/tests"
}

# Grab a copy of the tests repository
get_tests_repo()
{
[ -d "${test_repo_dir}" ] && return
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I doubt we need to, but if it already exists, should we do a pull/fetch on it to make sure it is upto date?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question but this test is only designed to run under the CI where everything is fresh.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tend to agree with Graham, sometimes I use CI scripts locally, not required in this PR we can let the user update test repository manually.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comments - #280 (comment).


mkdir -p "${kata_project_dir}"

git clone "${test_repo_url}" "${test_repo_dir}"
}

# Delete all local github repo clones.
#
# This is required to ensure that the tests themselves (re-)create these
# clones.
delete_kata_repos()
{
[ -n "${KATA_DEV_MODE}" ] && die "Not continuing as this is a dev system"
[ -z "${CI}" ] && die "Not continuing as this is a non-CI environment"

local cwd="$PWD"

info "Deleting all local kata repositories below ${kata_project_dir}"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a warning with a big red button :D

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As shown in the code, we only do this if running under a CI and developer mode is not enabled.


[ -d "${kata_project_dir}" ] && rm -rf "${kata_project_dir}" || true

# Recreate the empty directory, taking care to handle the scenario
# where the script is run from within the just-deleted directory.
mkdir -p "$cwd" && cd "$cwd"
}

setup()
{
source /etc/os-release || source /usr/lib/os-release

mkdir -p "${GOPATH}"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dunno if this will fail if GOPATH already exists? If so, a || true type fix I guess?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, no, -p won't fail if it exists.


get_tests_repo

[ -e "$mgr" ] || die "cannot find $mgr"
}

# Perform a simple test to create a container
create_kata_container()
{
local -r test_name="$1"

local -r msg=$(info "Successfully tested ${test_name} on distro ${ID} ${VERSION}")

# Perform a basic test
sudo -E docker run --rm -i --runtime "kata-runtime" "${docker_image}" echo "$msg"
}

# Run the kata manager to "execute" the install guide to ensure the commands
# it specified result in a working system.
test_distro_install_guide()
{
info "Installing system from the $ID install guide"

$mgr install-docker-system

$mgr configure-image
$mgr enable-debug

local mgr_name="${mgr##*/}"

local test_name="${mgr_name} to test install guide"

info "Install using ${test_name}"

create_kata_container "${test_name}"

# Clean up
$mgr remove-packages
}

# Apart from the distro-specific install guides, users can choose to install
# using one of the following methods:
#
# - kata-manager ("Automatic" method).
# - kata-doc-to-script ("Scripted" method).
#
# Testing these is awkward because we need to "execute" the documents
# describing those install methods, but since those install methods should
# themselves entirely document/handle an installation method, we need to
# convert each install document to a script, then delete all the kata code
# repositories. This ensures that when each install method script is run, it
# does not rely on any local files (it should download anything it needs). But
# since we're deleting the repos, we need to copy this script to a temporary
# location, along with the install scripts this function generates, and then
# re-exec this script with an option to ask it to run the scripts the previous
# instance of this script just generated.
test_alternative_install_methods()
{
local -a files
files+=("installing-with-kata-manager.md")
files+=("installing-with-kata-doc-to-script.md")

local tmp_dir

tmp_dir=$(mktemp -d)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we ever finally delete the tmp_dir? Maybe a TRAP hook like we use elsewhere might do it?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I'll fix that for when running with -t...

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it is fixed can you remove the FIXME?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


local script_file

local file

local tests_dir
tests_dir="${tmp_dir}/tests"

mkdir -p "${tests_dir}"

local -i num=0

# Convert the docs to scripts
for file in "${files[@]}"
do
num+=1

local file_path
local script_file
local script_file_path
local test_name

file_path="${script_dir}/../install/${file}"
script_file=${file/.md/.sh}

# Add a numeric prefix so the tests are run in the array order
test_name=$(printf "%.2d-%s" "${num}" "${script_file}")

script_file_path="${tests_dir}/${test_name}"

info "Creating test script ${test_name} from ${file}"

bash "${doc_to_script}" "${file_path}" "${script_file_path}"
done

reexec_in_tmpdir "${tmp_dir}"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is confusing :P thanks for document it

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

np.


# Not reached
die "re-exec failed"
}

run_tests()
{
[ -n "$TRAVIS" ] && info "Not testing install guide as Travis lacks modern distro support and VT-x" && return
test_distro_install_guide
test_alternative_install_methods
}

# Detect if any installation documents changed. If so, execute all the
# documents to test they result in a working system.
check_install_docs()
{
if [ -n "$TRAVIS" ]
then
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

about the code style :), isn't if [...]; then more widely used in kata scripts than having then on its own line?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't prescribe a coding style atm. However, we could if anyone wants to work on a new doc (and fight all the fights to get it landed :), or maybe it could be an update to:

info "Not testing install guide as Travis lacks modern distro support and VT-x"
return
fi

# List of filters used to restrict the types of file changes.
# See git-diff-tree(1) for further info.
Expand Down Expand Up @@ -50,35 +270,79 @@ check_install_guides()
# No files were changed
[ -z "$files" ] && return

changed=$(echo "$files" | grep "^install/.*\.md$" || true)
changed=$(echo "${files}" | grep "^install/.*\.md$" || true)

[ -z "$changed" ] && info "No install guides modified" && return
[ -z "$changed" ] && info "No install documents modified" && return

info "Found modified install guides: $changed"
info "Found modified install documents: ${changed}"

# Regardless of which distro install guide(s) were changed, we test
# Regardless of which installation documents were changed, we test
# them all where possible.
run_tests
}

local -r GOPATH=$(go env GOPATH)
[ -z "$GOPATH" ] && die "cannot determine GOPATH"
# Run the test scripts in the specified directory.
run_tests_from_dir()
{
local -r test_dir="$1"

local -r mgr="${GOPATH}/src/github.com/kata-containers/tests/cmd/kata-manager/kata-manager.sh"
[ -e "$test_dir" ] || die "invalid test dir: ${test_dir}"

[ ! -e "$GOPATH" ] && die "cannot find $mgr"
cd "${test_dir}"

source /etc/os-release
info "Looking for tests scripts to run in directory ${test_dir}"

info "Installing system from the $ID install guide"
for t in $(ls -- *.sh)
do
# Ensure the test script cannot access any local files
# (since it should be standalone and download any files
# it needs).
delete_kata_repos

$mgr install-docker-system
info "Running test script '$t'"
bash -x "${t}"

$mgr configure-image
$mgr enable-debug
# Ensure it is possible to use the installed system
create_kata_container "${t}"

msg="INFO: Successfully tested install guide for distro '$ID' $VERSION"
# Re-run setup to recreate the tests repo that was deleted
# before the test ran.
setup

# Perform a basic test
sudo -E docker run --rm -i --runtime "kata-runtime" busybox echo "$msg"
# Packaged install so clean up
# (Note that '$mgr' should now exist again)
$mgr remove-packages
done

# paranoia
[ -d "${test_dir}" ] && rm -rf "${test_dir}"

info "All tests passed"
}

main()
{
local opt
local test_dir

setup

while getopts "ht:" opt
do
case "$opt" in
h) usage; exit 0;;
t) test_dir="$OPTARG";;
*) die "invalid option: $opt";;
esac
done

if [ -n "$test_dir" ]
then
run_tests_from_dir "$test_dir"
exit 0
fi

check_install_docs
}

check_install_guides
main "$@"
29 changes: 19 additions & 10 deletions install/installing-with-kata-doc-to-script.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,34 @@ to generate installation bash scripts.
> install and configure the container manager manually.

## Packages Installation
```

```bash
$ source /etc/os-release
$ curl -fsSL -O https://raw.githubusercontent.com/kata-containers/documentation/master/install/${ID}-installation-guide.md
$ bash -c "$(curl -fsSL \
https://raw.githubusercontent.com/kata-containers/tests/master/.ci/kata-doc-to-script.sh) \
${ID}-installation-guide.md \
${ID}-install.sh"
$ bash -c "$(curl -fsSL https://raw.githubusercontent.com/kata-containers/tests/master/.ci/kata-doc-to-script.sh) ${ID}-installation-guide.md ${ID}-install.sh"
```

For example, if your distribution is CentOS, the previous example will generate a runnable shell script called `centos-install.sh`.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to separate the bash "./${ID}... command in a dedicate session?

E.g. For example, if your distribution is CentOS, the previous example will generate a runnable shell script called centos-install.sh. To proceed wit the installation, simply run:

$ bash "./${ID}-install.sh"

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure - I can do that. We'll have to source the os-release file yet again of course... ;)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

To proceed with the installation, run:

## Docker Installation and Setup
```bash
$ source /etc/os-release
$ bash "./${ID}-install.sh"
```

## Docker Installation and Setup

```bash
$ source /etc/os-release
$ curl -fsSL -O https://raw.githubusercontent.com/kata-containers/documentation/master/install/docker/${ID}-docker-install.md
$ bash -c "$(curl -fsSL \
https://raw.githubusercontent.com/kata-containers/tests/master/.ci/kata-doc-to-script.sh) \
${ID}-docker-install.md \
${ID}-docker-install.sh"
$ bash -c "$(curl -fsSL https://raw.githubusercontent.com/kata-containers/tests/master/.ci/kata-doc-to-script.sh) ${ID}-docker-install.md ${ID}-docker-install.sh"
```

For example, if your distribution is CentOS, this will generate a runnable shell script called `centos-docker-install.sh`.

To proceed with the Docker installation, run:

```bash
$ source /etc/os-release
$ bash "./${ID}-docker-install.sh"
```