summaryrefslogtreecommitdiffstats
path: root/test/lib/ansible_test/_util/target/setup/bootstrap.sh
diff options
context:
space:
mode:
Diffstat (limited to 'test/lib/ansible_test/_util/target/setup/bootstrap.sh')
-rw-r--r--test/lib/ansible_test/_util/target/setup/bootstrap.sh450
1 files changed, 450 insertions, 0 deletions
diff --git a/test/lib/ansible_test/_util/target/setup/bootstrap.sh b/test/lib/ansible_test/_util/target/setup/bootstrap.sh
new file mode 100644
index 0000000..732c122
--- /dev/null
+++ b/test/lib/ansible_test/_util/target/setup/bootstrap.sh
@@ -0,0 +1,450 @@
+# shellcheck shell=sh
+
+set -eu
+
+install_ssh_keys()
+{
+ if [ ! -f "${ssh_private_key_path}" ]; then
+ # write public/private ssh key pair
+ public_key_path="${ssh_private_key_path}.pub"
+
+ # shellcheck disable=SC2174
+ mkdir -m 0700 -p "${ssh_path}"
+ touch "${public_key_path}" "${ssh_private_key_path}"
+ chmod 0600 "${public_key_path}" "${ssh_private_key_path}"
+ echo "${ssh_public_key}" > "${public_key_path}"
+ echo "${ssh_private_key}" > "${ssh_private_key_path}"
+
+ # add public key to authorized_keys
+ authoried_keys_path="${HOME}/.ssh/authorized_keys"
+
+ # the existing file is overwritten to avoid conflicts (ex: RHEL on EC2 blocks root login)
+ cat "${public_key_path}" > "${authoried_keys_path}"
+ chmod 0600 "${authoried_keys_path}"
+
+ # add localhost's server keys to known_hosts
+ known_hosts_path="${HOME}/.ssh/known_hosts"
+
+ for key in /etc/ssh/ssh_host_*_key.pub; do
+ echo "localhost $(cat "${key}")" >> "${known_hosts_path}"
+ done
+ fi
+}
+
+customize_bashrc()
+{
+ true > ~/.bashrc
+
+ # Show color `ls` results when available.
+ if ls --color > /dev/null 2>&1; then
+ echo "alias ls='ls --color'" >> ~/.bashrc
+ elif ls -G > /dev/null 2>&1; then
+ echo "alias ls='ls -G'" >> ~/.bashrc
+ fi
+
+ # Improve shell prompts for interactive use.
+ echo "export PS1='\[\e]0;\u@\h: \w\a\]\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '" >> ~/.bashrc
+}
+
+install_pip() {
+ if ! "${python_interpreter}" -m pip.__main__ --version --disable-pip-version-check 2>/dev/null; then
+ case "${python_version}" in
+ "2.7")
+ pip_bootstrap_url="https://ci-files.testing.ansible.com/ansible-test/get-pip-20.3.4.py"
+ ;;
+ *)
+ pip_bootstrap_url="https://ci-files.testing.ansible.com/ansible-test/get-pip-21.3.1.py"
+ ;;
+ esac
+
+ while true; do
+ curl --silent --show-error "${pip_bootstrap_url}" -o /tmp/get-pip.py && \
+ "${python_interpreter}" /tmp/get-pip.py --disable-pip-version-check --quiet && \
+ rm /tmp/get-pip.py \
+ && break
+ echo "Failed to install packages. Sleeping before trying again..."
+ sleep 10
+ done
+ fi
+}
+
+pip_install() {
+ pip_packages="$1"
+
+ while true; do
+ # shellcheck disable=SC2086
+ "${python_interpreter}" -m pip install --disable-pip-version-check ${pip_packages} \
+ && break
+ echo "Failed to install packages. Sleeping before trying again..."
+ sleep 10
+ done
+}
+
+bootstrap_remote_alpine()
+{
+ py_pkg_prefix="py3"
+
+ packages="
+ acl
+ bash
+ gcc
+ python3-dev
+ ${py_pkg_prefix}-pip
+ sudo
+ "
+
+ if [ "${controller}" ]; then
+ packages="
+ ${packages}
+ ${py_pkg_prefix}-cryptography
+ ${py_pkg_prefix}-packaging
+ ${py_pkg_prefix}-yaml
+ ${py_pkg_prefix}-jinja2
+ ${py_pkg_prefix}-resolvelib
+ "
+ fi
+
+ while true; do
+ # shellcheck disable=SC2086
+ apk add -q ${packages} \
+ && break
+ echo "Failed to install packages. Sleeping before trying again..."
+ sleep 10
+ done
+}
+
+bootstrap_remote_fedora()
+{
+ py_pkg_prefix="python3"
+
+ packages="
+ acl
+ gcc
+ ${py_pkg_prefix}-devel
+ "
+
+ if [ "${controller}" ]; then
+ packages="
+ ${packages}
+ ${py_pkg_prefix}-cryptography
+ ${py_pkg_prefix}-jinja2
+ ${py_pkg_prefix}-packaging
+ ${py_pkg_prefix}-pyyaml
+ ${py_pkg_prefix}-resolvelib
+ "
+ fi
+
+ while true; do
+ # shellcheck disable=SC2086
+ dnf install -q -y ${packages} \
+ && break
+ echo "Failed to install packages. Sleeping before trying again..."
+ sleep 10
+ done
+}
+
+bootstrap_remote_freebsd()
+{
+ packages="
+ python${python_package_version}
+ py${python_package_version}-sqlite3
+ bash
+ curl
+ gtar
+ sudo
+ "
+
+ if [ "${controller}" ]; then
+ jinja2_pkg="py${python_package_version}-jinja2"
+ cryptography_pkg="py${python_package_version}-cryptography"
+ pyyaml_pkg="py${python_package_version}-yaml"
+
+ # Declare platform/python version combinations which do not have supporting OS packages available.
+ # For these combinations ansible-test will use pip to install the requirements instead.
+ case "${platform_version}/${python_version}" in
+ *)
+ jinja2_pkg="" # not available
+ cryptography_pkg="" # not available
+ pyyaml_pkg="" # not available
+ ;;
+ esac
+
+ packages="
+ ${packages}
+ libyaml
+ ${pyyaml_pkg}
+ ${jinja2_pkg}
+ ${cryptography_pkg}
+ "
+ fi
+
+ while true; do
+ # shellcheck disable=SC2086
+ env ASSUME_ALWAYS_YES=YES pkg bootstrap && \
+ pkg install -q -y ${packages} \
+ && break
+ echo "Failed to install packages. Sleeping before trying again..."
+ sleep 10
+ done
+
+ install_pip
+
+ if ! grep '^PermitRootLogin yes$' /etc/ssh/sshd_config > /dev/null; then
+ sed -i '' 's/^# *PermitRootLogin.*$/PermitRootLogin yes/;' /etc/ssh/sshd_config
+ service sshd restart
+ fi
+
+ # make additional wheels available for packages which lack them for this platform
+ echo "# generated by ansible-test
+[global]
+extra-index-url = https://spare-tire.testing.ansible.com/simple/
+prefer-binary = yes
+" > /etc/pip.conf
+
+ # enable ACL support on the root filesystem (required for become between unprivileged users)
+ fs_path="/"
+ fs_device="$(mount -v "${fs_path}" | cut -w -f 1)"
+ # shellcheck disable=SC2001
+ fs_device_escaped=$(echo "${fs_device}" | sed 's|/|\\/|g')
+
+ mount -o acls "${fs_device}" "${fs_path}"
+ awk 'BEGIN{FS=" "}; /'"${fs_device_escaped}"'/ {gsub(/^rw$/,"rw,acls", $4); print; next} // {print}' /etc/fstab > /etc/fstab.new
+ mv /etc/fstab.new /etc/fstab
+
+ # enable sudo without a password for the wheel group, allowing ansible to use the sudo become plugin
+ echo '%wheel ALL=(ALL:ALL) NOPASSWD: ALL' > /usr/local/etc/sudoers.d/ansible-test
+}
+
+bootstrap_remote_macos()
+{
+ # Silence macOS deprecation warning for bash.
+ echo "export BASH_SILENCE_DEPRECATION_WARNING=1" >> ~/.bashrc
+
+ # Make sure ~/ansible/ is the starting directory for interactive shells on the control node.
+ # The root home directory is under a symlink. Without this the real path will be displayed instead.
+ if [ "${controller}" ]; then
+ echo "cd ~/ansible/" >> ~/.bashrc
+ fi
+
+ # Make sure commands like 'brew' can be found.
+ # This affects users with the 'zsh' shell, as well as 'root' accessed using 'sudo' from a user with 'zsh' for a shell.
+ # shellcheck disable=SC2016
+ echo 'PATH="/usr/local/bin:$PATH"' > /etc/zshenv
+}
+
+bootstrap_remote_rhel_7()
+{
+ packages="
+ gcc
+ python-devel
+ python-virtualenv
+ "
+
+ while true; do
+ # shellcheck disable=SC2086
+ yum install -q -y ${packages} \
+ && break
+ echo "Failed to install packages. Sleeping before trying again..."
+ sleep 10
+ done
+
+ install_pip
+
+ bootstrap_remote_rhel_pinned_pip_packages
+}
+
+bootstrap_remote_rhel_8()
+{
+ if [ "${python_version}" = "3.6" ]; then
+ py_pkg_prefix="python3"
+ else
+ py_pkg_prefix="python${python_package_version}"
+ fi
+
+ packages="
+ gcc
+ ${py_pkg_prefix}-devel
+ "
+
+ # Jinja2 is not installed with an OS package since the provided version is too old.
+ # Instead, ansible-test will install it using pip.
+ if [ "${controller}" ]; then
+ packages="
+ ${packages}
+ ${py_pkg_prefix}-cryptography
+ "
+ fi
+
+ while true; do
+ # shellcheck disable=SC2086
+ yum module install -q -y "python${python_package_version}" && \
+ yum install -q -y ${packages} \
+ && break
+ echo "Failed to install packages. Sleeping before trying again..."
+ sleep 10
+ done
+
+ bootstrap_remote_rhel_pinned_pip_packages
+}
+
+bootstrap_remote_rhel_9()
+{
+ py_pkg_prefix="python3"
+
+ packages="
+ gcc
+ ${py_pkg_prefix}-devel
+ "
+
+ # Jinja2 is not installed with an OS package since the provided version is too old.
+ # Instead, ansible-test will install it using pip.
+ if [ "${controller}" ]; then
+ packages="
+ ${packages}
+ ${py_pkg_prefix}-cryptography
+ ${py_pkg_prefix}-packaging
+ ${py_pkg_prefix}-pyyaml
+ ${py_pkg_prefix}-resolvelib
+ "
+ fi
+
+ while true; do
+ # shellcheck disable=SC2086
+ dnf install -q -y ${packages} \
+ && break
+ echo "Failed to install packages. Sleeping before trying again..."
+ sleep 10
+ done
+}
+
+bootstrap_remote_rhel()
+{
+ case "${platform_version}" in
+ 7.*) bootstrap_remote_rhel_7 ;;
+ 8.*) bootstrap_remote_rhel_8 ;;
+ 9.*) bootstrap_remote_rhel_9 ;;
+ esac
+}
+
+bootstrap_remote_rhel_pinned_pip_packages()
+{
+ # pin packaging and pyparsing to match the downstream vendored versions
+ pip_packages="
+ packaging==20.4
+ pyparsing==2.4.7
+ "
+
+ pip_install "${pip_packages}"
+}
+
+bootstrap_remote_ubuntu()
+{
+ py_pkg_prefix="python3"
+
+ packages="
+ acl
+ gcc
+ python${python_version}-dev
+ python3-pip
+ python${python_version}-venv
+ "
+
+ if [ "${controller}" ]; then
+ cryptography_pkg="${py_pkg_prefix}-cryptography"
+ jinja2_pkg="${py_pkg_prefix}-jinja2"
+ packaging_pkg="${py_pkg_prefix}-packaging"
+ pyyaml_pkg="${py_pkg_prefix}-yaml"
+ resolvelib_pkg="${py_pkg_prefix}-resolvelib"
+
+ # Declare platforms which do not have supporting OS packages available.
+ # For these ansible-test will use pip to install the requirements instead.
+ # Only the platform is checked since Ubuntu shares Python packages across Python versions.
+ case "${platform_version}" in
+ "20.04")
+ jinja2_pkg="" # too old
+ resolvelib_pkg="" # not available
+ ;;
+ esac
+
+ packages="
+ ${packages}
+ ${cryptography_pkg}
+ ${jinja2_pkg}
+ ${packaging_pkg}
+ ${pyyaml_pkg}
+ ${resolvelib_pkg}
+ "
+ fi
+
+ while true; do
+ # shellcheck disable=SC2086
+ apt-get update -qq -y && \
+ DEBIAN_FRONTEND=noninteractive apt-get install -qq -y --no-install-recommends ${packages} \
+ && break
+ echo "Failed to install packages. Sleeping before trying again..."
+ sleep 10
+ done
+
+ if [ "${controller}" ]; then
+ if [ "${platform_version}/${python_version}" = "20.04/3.9" ]; then
+ # Install pyyaml using pip so libyaml support is available on Python 3.9.
+ # The OS package install (which is installed by default) only has a .so file for Python 3.8.
+ pip_install "--upgrade pyyaml"
+ fi
+ fi
+}
+
+bootstrap_docker()
+{
+ # Required for newer mysql-server packages to install/upgrade on Ubuntu 16.04.
+ rm -f /usr/sbin/policy-rc.d
+}
+
+bootstrap_remote()
+{
+ for python_version in ${python_versions}; do
+ echo "Bootstrapping Python ${python_version}"
+
+ python_interpreter="python${python_version}"
+ python_package_version="$(echo "${python_version}" | tr -d '.')"
+
+ case "${platform}" in
+ "alpine") bootstrap_remote_alpine ;;
+ "fedora") bootstrap_remote_fedora ;;
+ "freebsd") bootstrap_remote_freebsd ;;
+ "macos") bootstrap_remote_macos ;;
+ "rhel") bootstrap_remote_rhel ;;
+ "ubuntu") bootstrap_remote_ubuntu ;;
+ esac
+ done
+}
+
+bootstrap()
+{
+ ssh_path="${HOME}/.ssh"
+ ssh_private_key_path="${ssh_path}/id_${ssh_key_type}"
+
+ install_ssh_keys
+ customize_bashrc
+
+ # allow tests to detect ansible-test bootstrapped instances, as well as the bootstrap type
+ echo "${bootstrap_type}" > /etc/ansible-test.bootstrap
+
+ case "${bootstrap_type}" in
+ "docker") bootstrap_docker ;;
+ "remote") bootstrap_remote ;;
+ esac
+}
+
+# These variables will be templated before sending the script to the host.
+# They are at the end of the script to maintain line numbers for debugging purposes.
+bootstrap_type=#{bootstrap_type}
+controller=#{controller}
+platform=#{platform}
+platform_version=#{platform_version}
+python_versions=#{python_versions}
+ssh_key_type=#{ssh_key_type}
+ssh_private_key=#{ssh_private_key}
+ssh_public_key=#{ssh_public_key}
+
+bootstrap