|
|
|
# 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="
|
|
|
|
bash
|
|
|
|
gcc
|
|
|
|
python3-dev
|
|
|
|
${py_pkg_prefix}-pip
|
|
|
|
"
|
|
|
|
|
|
|
|
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="
|
|
|
|
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
|
|
|
|
"12.3/3.8")
|
|
|
|
;;
|
|
|
|
"13.1/3.8")
|
|
|
|
;;
|
|
|
|
*)
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
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="
|
|
|
|
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}
|
|
|
|
"
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
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
|