From 0d64e870af1f862dda7d0c7d98586f3dfdf3a2ea Mon Sep 17 00:00:00 2001 From: Ian Pittwood Date: Thu, 18 Apr 2024 14:04:42 -0700 Subject: [PATCH] Extract common operations to reusable scripts in base images (#716) * Fix/exclude goss tests for buildx bake * Implement separate test for Connect * Implement bake preview builds * Provision buildx in preview * Do not cache or output tests for preview Provide a buildx config for GHA Unify test sleep behavior of Workbench images * Remove test targets * Remove test layers from Dockerfiles * Change test running to be orchestrated by a Python script * Update preview builds for new test script * Create common use scripts in base image for Ubuntu 22.04 images * Create common use scripts in base image for CentOS 7 images * Move deps to subdirectory Fix hadolint issues * Ignore hadolint issue * Update permissions hex for tests * Remove build.justfile * Remove unnecessary buildx setup from build-bake-preview.yaml * Move libarchive-dev to ubuntu2204_packages.txt --- product/base/Dockerfile.centos7 | 65 ++---- product/base/Dockerfile.ubuntu2204 | 114 ++-------- product/base/deps/centos7_packages.txt | 20 ++ product/base/deps/requirements.txt | 2 + product/base/deps/ubuntu2204_packages.txt | 66 ++++++ product/base/scripts/rhel/install_drivers.sh | 21 ++ product/base/scripts/rhel/install_python.sh | 118 ++++++++++ product/base/scripts/rhel/install_quarto.sh | 75 +++++++ product/base/scripts/rhel/install_r.sh | 173 +++++++++++++++ product/base/scripts/rhel/yum.sh | 112 ++++++++++ product/base/scripts/ubuntu/apt.sh | 118 ++++++++++ .../base/scripts/ubuntu/install_drivers.sh | 21 ++ product/base/scripts/ubuntu/install_python.sh | 115 ++++++++++ product/base/scripts/ubuntu/install_quarto.sh | 75 +++++++ product/base/scripts/ubuntu/install_r.sh | 208 ++++++++++++++++++ product/base/test/goss.yaml | 22 ++ product/pro/Dockerfile.centos7 | 17 +- product/pro/Dockerfile.ubuntu2204 | 20 +- product/pro/deps/r_packages.txt | 1 + 19 files changed, 1203 insertions(+), 160 deletions(-) create mode 100644 product/base/deps/centos7_packages.txt create mode 100644 product/base/deps/requirements.txt create mode 100644 product/base/deps/ubuntu2204_packages.txt create mode 100755 product/base/scripts/rhel/install_drivers.sh create mode 100755 product/base/scripts/rhel/install_python.sh create mode 100755 product/base/scripts/rhel/install_quarto.sh create mode 100755 product/base/scripts/rhel/install_r.sh create mode 100755 product/base/scripts/rhel/yum.sh create mode 100755 product/base/scripts/ubuntu/apt.sh create mode 100755 product/base/scripts/ubuntu/install_drivers.sh create mode 100755 product/base/scripts/ubuntu/install_python.sh create mode 100755 product/base/scripts/ubuntu/install_quarto.sh create mode 100755 product/base/scripts/ubuntu/install_r.sh create mode 100644 product/pro/deps/r_packages.txt diff --git a/product/base/Dockerfile.centos7 b/product/base/Dockerfile.centos7 index f000c432..a0c51b31 100644 --- a/product/base/Dockerfile.centos7 +++ b/product/base/Dockerfile.centos7 @@ -8,30 +8,17 @@ ARG PYTHON_VERSION_ALT=3.8.15 ARG TINI_VERSION=0.19.0 ARG QUARTO_VERSION=1.3.340 +ARG SCRIPTS_DIR=/opt/positscripts + +COPY scripts/rhel/* ${SCRIPTS_DIR}/ + ### Update/upgrade system packages ### -RUN yum upgrade -y -q \ - && yum install -y -q \ - epel-release \ - && yum install -y -q \ - bzip2 \ - git \ - gpg \ - gpg-agent \ - libcurl-devel \ - libuser-devel \ - libxml2-devel \ - openssl-devel \ - openssh-clients \ - pandoc \ - perl-Digest-MD5 \ - postgresql-libs \ - rrdtool \ - sudo \ - unixODBC \ - unixODBC-devel \ - wget \ - which \ - && yum clean all +COPY deps/centos7_packages.txt /tmp/packages.txt +# hadolint ignore=SC2046 +RUN ${SCRIPTS_DIR}/yum.sh --update upgrade \ + && ${SCRIPTS_DIR}/yum.sh install epel-release \ + && ${SCRIPTS_DIR}/yum.sh install $(cat /tmp/packages.txt) \ + && ${SCRIPTS_DIR}/yum.sh --clean ### Install tini ### ADD https://cdn.rstudio.com/platform/tini/v${TINI_VERSION}/tini-amd64 /tini @@ -50,37 +37,22 @@ RUN curl -sL "https://yihui.org/tinytex/install-bin-unix.sh" | sh \ && /opt/TinyTeX/bin/*/tlmgr path add ### Install Quarto ### -RUN curl -o quarto.tar.gz -L https://github.com/quarto-dev/quarto-cli/releases/download/v${QUARTO_VERSION}/quarto-${QUARTO_VERSION}-linux-amd64.tar.gz \ - && mkdir -p /opt/quarto/${QUARTO_VERSION} \ - && tar -zxvf quarto.tar.gz -C "/opt/quarto/${QUARTO_VERSION}" --strip-components=1 \ - && rm -f quarto.tar.gz \ +RUN QUARTO_VERSION=${QUARTO_VERSION} ${SCRIPTS_DIR}/install_quarto.sh \ && ln -s /opt/quarto/${QUARTO_VERSION}/bin/quarto /usr/local/bin/quarto ### Install R versions ### -RUN curl -O https://cdn.rstudio.com/r/centos-7/pkgs/R-${R_VERSION}-1-1.x86_64.rpm \ - && curl -O https://cdn.rstudio.com/r/centos-7/pkgs/R-${R_VERSION_ALT}-1-1.x86_64.rpm \ - && yum install -y R-${R_VERSION}-1-1.x86_64.rpm \ - && yum install -y R-${R_VERSION_ALT}-1-1.x86_64.rpm \ - && yum clean all \ - && rm -rf R-${R_VERSION}-1-1.x86_64.rpm \ - && rm -rf R-${R_VERSION_ALT}-1-1.x86_64.rpm \ +RUN R_VERSION=${R_VERSION} ${SCRIPTS_DIR}/install_r.sh \ + && R_VERSION=${R_VERSION_ALT} ${SCRIPTS_DIR}/install_r.sh \ && ln -s /opt/R/${R_VERSION} /opt/R/default \ && ln -s /opt/R/default/bin/R /usr/local/bin/R \ && ln -s /opt/R/default/bin/Rscript /usr/local/bin/Rscript ### Install Python versions ### -RUN curl -O https://cdn.rstudio.com/python/centos-7/pkgs/python-${PYTHON_VERSION}-1-1.x86_64.rpm \ - && curl -O https://cdn.rstudio.com/python/centos-7/pkgs/python-${PYTHON_VERSION_ALT}-1-1.x86_64.rpm \ - && yum install -y python-${PYTHON_VERSION}-1-1.x86_64.rpm \ - && yum install -y python-${PYTHON_VERSION_ALT}-1-1.x86_64.rpm \ - && yum clean all \ - && rm -rf python-${PYTHON_VERSION}-1-1.x86_64.rpm \ - && rm -rf python-${PYTHON_VERSION_ALT}-1-1.x86_64.rpm \ - && /opt/python/${PYTHON_VERSION}/bin/python3 -m pip install 'virtualenv<20' \ - && /opt/python/${PYTHON_VERSION}/bin/python3 -m pip install --upgrade setuptools \ - && /opt/python/${PYTHON_VERSION_ALT}/bin/python3 -m pip install 'virtualenv<20' \ - && /opt/python/${PYTHON_VERSION_ALT}/bin/python3 -m pip install --upgrade setuptools \ - && ln -s /opt/python/${PYTHON_VERSION} /opt/python/default +COPY deps/requirements.txt /tmp/requirements.txt +RUN PYTHON_VERSION=${PYTHON_VERSION} ${SCRIPTS_DIR}/install_python.sh -r /tmp/requirements.txt \ + && PYTHON_VERSION=${PYTHON_VERSION_ALT} ${SCRIPTS_DIR}/install_python.sh -r /tmp/requirements.txt \ + && ln -s /opt/python/${PYTHON_VERSION} /opt/python/default \ + && rm -f /tmp/requirements.txt ### Locale configuration ### RUN localedef -i en_US -f UTF-8 en_US.UTF-8 @@ -88,7 +60,6 @@ ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 - LABEL posit.r.version="${R_VERSION}" \ posit.r.version_alt="${R_VERSION_ALT}" \ posit.python.version="${PYTHON_VERSION}" \ diff --git a/product/base/Dockerfile.ubuntu2204 b/product/base/Dockerfile.ubuntu2204 index e848521f..8f21bc19 100644 --- a/product/base/Dockerfile.ubuntu2204 +++ b/product/base/Dockerfile.ubuntu2204 @@ -9,74 +9,18 @@ ARG PYTHON_VERSION_ALT=3.8.17 ARG TINI_VERSION=0.19.0 ARG QUARTO_VERSION=1.3.340 +ARG SCRIPTS_DIR=/opt/positscripts + +COPY scripts/ubuntu/* ${SCRIPTS_DIR}/ + ### Update/upgrade system packages ### -RUN apt-get update --fix-missing \ - && apt-get upgrade -yq \ - && apt-get install -yq --no-install-recommends \ - apt-transport-https \ - ca-certificates \ - cmake \ - cracklib-runtime \ - curl \ - default-jdk \ - dirmngr \ - dpkg-sig \ - g++ \ - gcc \ - gdal-bin \ - gfortran \ - git \ - gpg \ - gpg-agent \ - gsfonts \ - imagemagick \ - libarchive-dev \ - libcairo2-dev \ - libcurl4-openssl-dev \ - libev-dev \ - libfontconfig1-dev \ - libfreetype6-dev \ - libfribidi-dev \ - libgdal-dev \ - libgeos-dev \ - libgl1-mesa-dev \ - libglpk-dev \ - libglu1-mesa-dev \ - libgmp3-dev \ - libharfbuzz-dev \ - libicu-dev \ - libjpeg-dev \ - libmagick++-dev \ - libmysqlclient-dev \ - libopenblas-dev \ - libpaper-utils \ - libpcre2-dev \ - libpng-dev \ - libproj-dev \ - libsodium-dev \ - libssh2-1-dev \ - libssl-dev \ - libtiff-dev \ - libudunits2-dev \ - libv8-dev \ - libxml2-dev \ - locales \ - make \ - openssh-client \ - pandoc \ - perl \ - sudo \ - tcl \ - tk \ - tk-dev \ - tk-table \ - tzdata \ - unixodbc-dev \ - unzip \ - wget \ - zip \ - zlib1g-dev \ - && rm -rf /var/lib/apt/lists/* +COPY deps/ubuntu2204_packages.txt /tmp/apt_packages.txt +# hadolint ignore=SC2046 +RUN ${SCRIPTS_DIR}/apt.sh --update install lsof \ + && ${SCRIPTS_DIR}/apt.sh --update upgrade \ + && ${SCRIPTS_DIR}/apt.sh install $(cat /tmp/apt_packages.txt) \ + && ${SCRIPTS_DIR}/apt.sh --clean \ + && rm -f /tmp/apt_packages.txt ### Install tini ### ADD https://cdn.rstudio.com/platform/tini/v${TINI_VERSION}/tini-amd64 /tini @@ -95,35 +39,22 @@ RUN curl -sL "https://yihui.org/tinytex/install-bin-unix.sh" | sh \ && /opt/TinyTeX/bin/*/tlmgr path add ### Install Quarto ### -RUN curl -o quarto.tar.gz -L https://github.com/quarto-dev/quarto-cli/releases/download/v${QUARTO_VERSION}/quarto-${QUARTO_VERSION}-linux-amd64.tar.gz \ - && mkdir -p /opt/quarto/${QUARTO_VERSION} \ - && tar -zxvf quarto.tar.gz -C "/opt/quarto/${QUARTO_VERSION}" --strip-components=1 \ - && rm -f quarto.tar.gz \ +RUN QUARTO_VERSION=${QUARTO_VERSION} ${SCRIPTS_DIR}/install_quarto.sh \ && ln -s /opt/quarto/${QUARTO_VERSION}/bin/quarto /usr/local/bin/quarto ### Install R versions ### -RUN curl -O https://cdn.rstudio.com/r/ubuntu-2204/pkgs/r-${R_VERSION}_1_amd64.deb \ - && curl -O https://cdn.rstudio.com/r/ubuntu-2204/pkgs/r-${R_VERSION_ALT}_1_amd64.deb \ - && apt-get install -yq --no-install-recommends ./r-${R_VERSION}_1_amd64.deb \ - && apt-get install -yq --no-install-recommends ./r-${R_VERSION_ALT}_1_amd64.deb \ - && rm -f ./r-${R_VERSION}_1_amd64.deb \ - && rm -f ./r-${R_VERSION_ALT}_1_amd64.deb \ +RUN R_VERSION=${R_VERSION} ${SCRIPTS_DIR}/install_r.sh \ + && R_VERSION=${R_VERSION_ALT} ${SCRIPTS_DIR}/install_r.sh \ && ln -s /opt/R/${R_VERSION} /opt/R/default \ && ln -s /opt/R/default/bin/R /usr/local/bin/R \ && ln -s /opt/R/default/bin/Rscript /usr/local/bin/Rscript ### Install Python versions ### -RUN curl -O https://cdn.rstudio.com/python/ubuntu-2204/pkgs/python-${PYTHON_VERSION}_1_amd64.deb \ - && curl -O https://cdn.rstudio.com/python/ubuntu-2204/pkgs/python-${PYTHON_VERSION_ALT}_1_amd64.deb \ - && apt-get install -yq --no-install-recommends ./python-${PYTHON_VERSION}_1_amd64.deb \ - && apt-get install -yq --no-install-recommends ./python-${PYTHON_VERSION_ALT}_1_amd64.deb \ - && rm -rf python-${PYTHON_VERSION}_1_amd64.deb \ - && rm -rf python-${PYTHON_VERSION_ALT}_1_amd64.deb \ - && /opt/python/${PYTHON_VERSION}/bin/python3 -m pip install 'virtualenv<20' \ - && /opt/python/${PYTHON_VERSION}/bin/python3 -m pip install --upgrade setuptools \ - && /opt/python/${PYTHON_VERSION_ALT}/bin/python3 -m pip install 'virtualenv<20' \ - && /opt/python/${PYTHON_VERSION_ALT}/bin/python3 -m pip install --upgrade setuptools \ - && ln -s /opt/python/${PYTHON_VERSION} /opt/python/default +COPY deps/requirements.txt /tmp/requirements.txt +RUN PYTHON_VERSION=${PYTHON_VERSION} ${SCRIPTS_DIR}/install_python.sh -r /tmp/requirements.txt \ + && PYTHON_VERSION=${PYTHON_VERSION_ALT} ${SCRIPTS_DIR}/install_python.sh -r /tmp/requirements.txt \ + && ln -s /opt/python/${PYTHON_VERSION} /opt/python/default \ + && rm -f /tmp/requirements.txt ### Locale configuration ### RUN localedef -i en_US -f UTF-8 en_US.UTF-8 @@ -132,13 +63,6 @@ ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 ENV TZ=UTC -### Clean up ### -RUN apt-get install -yqf --no-install-recommends \ - && apt-get autoremove \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* - - LABEL posit.r.version="${R_VERSION}" \ posit.r.version_alt="${R_VERSION_ALT}" \ posit.python.version="${PYTHON_VERSION}" \ diff --git a/product/base/deps/centos7_packages.txt b/product/base/deps/centos7_packages.txt new file mode 100644 index 00000000..cd91ab88 --- /dev/null +++ b/product/base/deps/centos7_packages.txt @@ -0,0 +1,20 @@ +bzip2 +curl +git +gpg +gpg-agent +libcurl-devel +libuser-devel +libxml2-devel +openssl-devel +openssh-clients +pandoc +perl-Digest-MD5 +postgresql-libs +redhat-lsb-core +rrdtool +sudo +unixODBC +unixODBC-devel +wget +which \ No newline at end of file diff --git a/product/base/deps/requirements.txt b/product/base/deps/requirements.txt new file mode 100644 index 00000000..0df1a18f --- /dev/null +++ b/product/base/deps/requirements.txt @@ -0,0 +1,2 @@ +virtualenv<20 +setuptools diff --git a/product/base/deps/ubuntu2204_packages.txt b/product/base/deps/ubuntu2204_packages.txt new file mode 100644 index 00000000..3a836e5c --- /dev/null +++ b/product/base/deps/ubuntu2204_packages.txt @@ -0,0 +1,66 @@ +apt-transport-https +build-essential +ca-certificates +cmake +cracklib-runtime +curl +default-jdk +dirmngr +dpkg-sig +g++ +gcc +gdal-bin +gfortran +git +gnupg2 +gpg +gpg-agent +gsfonts +imagemagick +libarchive-dev +libcairo2-dev +libcurl4-openssl-dev +libev-dev +libfontconfig1-dev +libfreetype6-dev +libfribidi-dev +libgdal-dev +libgeos-dev +libgl1-mesa-dev +libglpk-dev +libglu1-mesa-dev +libgmp3-dev +libharfbuzz-dev +libicu-dev +libjpeg-dev +libmagick++-dev +libmysqlclient-dev +libopenblas-dev +libpaper-utils +libpcre2-dev +libpng-dev +libproj-dev +libsodium-dev +libssh2-1-dev +libssl-dev +libtiff-dev +libudunits2-dev +libv8-dev +libxml2-dev +locales +lsb-release +make +openssh-client +pandoc +perl +sudo +tcl +tk +tk-dev +tk-table +tzdata +unixodbc-dev +unzip +wget +zip +zlib1g-dev \ No newline at end of file diff --git a/product/base/scripts/rhel/install_drivers.sh b/product/base/scripts/rhel/install_drivers.sh new file mode 100755 index 00000000..40538b10 --- /dev/null +++ b/product/base/scripts/rhel/install_drivers.sh @@ -0,0 +1,21 @@ +#!/bin/bash +set -exo pipefail +export DEBIAN_FRONTEND=noninteractive + +# Output delimiter +d="====" + +if [ -z "$DRIVERS_VERSION" ]; then + echo "$d No DRIVERS_VERSION specified $d" + exit 1 +fi + +echo "$d$d Installing Professional Drivers ${DRIVERS_VERSION} $d$d" + +drivers_url="https://cdn.rstudio.com/drivers/7C152C12/installer/rstudio-drivers-${DRIVERS_VERSION}.el.x86_64.rpm" +curl -sL "$drivers_url" -o "/tmp/rstudio-drivers_${DRIVERS_VERSION}.el.x86_64.rpm" + +yum install -y -q "/tmp/rstudio-drivers_${DRIVERS_VERSION}.el.x86_64.rpm" +cat /opt/rstudio-drivers/odbcinst.ini.sample > /etc/odbcinst.ini + +rm /tmp/rstudio-drivers_${DRIVERS_VERSION}.el.x86_64.rpm diff --git a/product/base/scripts/rhel/install_python.sh b/product/base/scripts/rhel/install_python.sh new file mode 100755 index 00000000..ecf32923 --- /dev/null +++ b/product/base/scripts/rhel/install_python.sh @@ -0,0 +1,118 @@ +#!/bin/bash +set -eo pipefail +export DEBIAN_FRONTEND=noninteractive + +# Output delimiter +d="====" + +usage() { + echo "Usage:" + echo " $0 [OPTIONS]" + echo "" + echo "Examples:" + echo " # Install Python version specified by PYTHON_VERSION environment variable" + echo " $0" + echo " # Install Python 3.10.4" + echo " PYTHON_VERSION=3.10.4 $0" + echo " # Install Python and packages listed in /tmp/pythonh_packages.txt" + echo " PYTHON_VERSION=3.11.1 $0 -r /tmp/r_packages.txt" + echo "" + echo "Options:" + echo " -d, --debug Enable debug output" + echo " -h, --help Print usage and exit" + echo " --prefix Install Python to a custom prefix" + echo " Each version of Python will have its own subdirectory" + echo " Default: /opt/python" + echo " -r, --requirement " + echo " Install python packages from a requirements file" +} + + +# Set defaults +if [ -z "${DISTRO}" ]; then + DISTRO=$(lsb_release -is | tr '[:upper:]' '[:lower:]') +fi +if [ -z "${OS_VERSION}" ]; then + OS_VERSION=$(rpm -E %{rhel}) +fi +YUM_ARGS="-y -q" +PREFIX="/opt/python" + +OPTIONS=$(getopt -o hdr: --long help,debug,prefix:,requirement: -- "$@") +# shellcheck disable=SC2181 +if [[ $? -ne 0 ]]; then + exit 1; +fi + +eval set -- "$OPTIONS" +while true; do + case "$1" in + -d | --debug) + set -x + shift + ;; + -h | --help) + usage + shift + exit + ;; + --prefix) + PREFIX="$2" + shift 2 + ;; + -r | --requirement) + PYTHON_PKG_FILE="$2" + shift 2 + ;; + --) shift; + break + ;; + esac +done + +if [ -z "$PYTHON_VERSION" ]; then + usage + exit 1 +fi + +# Set python binary path +PYTHON_BIN="${PREFIX}/${PYTHON_VERSION}/bin/python" + +# Set yum options +YUM_ARGS="-y -q" + +install_python() { + # Check if Python is already installed + if $PYTHON_BIN --version | grep -qE "^Python ${PYTHON_VERSION}" ; then + echo "$d Python $PYTHON_VERSION is already installed in $PREFIX/$PYTHON_VERSION $d" + return + fi + + echo "$d$d Installing Python $PYTHON_VERSION to $PREFIX/$PYTHON_VERSION $d$d" + mkdir -p "$PREFIX" + + local python_url="https://cdn.rstudio.com/python/${DISTRO}-${OS_VERSION}/pkgs/python-${PYTHON_VERSION}-1-1.x86_64.rpm" + curl -sL "$python_url" -o "/tmp/python-${PYTHON_VERSION}.rpm" + + # shellcheck disable=SC2086 + yum install $YUM_ARGS "/tmp/python-${PYTHON_VERSION}.rpm" + rm "/tmp/python-${PYTHON_VERSION}.rpm" + # Upgrade pip to latest version + $PYTHON_BIN -m pip install -U pip +} + +install_python_packages() { + if [ ! -f "$PYTHON_PKG_FILE" ]; then + echo "$d Python package file $PYTHON_PKG_FILE does not exist $d" + exit 1 + fi + + echo "$d$d Installing python-${PYTHON_VERSION} packages from ${PYTHON_PKG_FILE} $d$d" + $PYTHON_BIN -m pip install -U pip + $PYTHON_BIN -m pip install -r "$PYTHON_PKG_FILE" +} + +install_python +if [ -n "$PYTHON_PKG_FILE" ]; then + install_python_packages +fi diff --git a/product/base/scripts/rhel/install_quarto.sh b/product/base/scripts/rhel/install_quarto.sh new file mode 100755 index 00000000..e6071b13 --- /dev/null +++ b/product/base/scripts/rhel/install_quarto.sh @@ -0,0 +1,75 @@ +#!/bin/bash +set -eo pipefail +export DEBIAN_FRONTEND=noninteractive + +# Output delimiter +d="====" + +usage() { + echo "Usage:" + echo " $0 [OPTIONS]" + echo "" + echo "Examples:" + echo " # Install Quarto version specified by QUARTO_VERSION environment variable" + echo " $0" + echo " # Install Quarto 1.3.340" + echo " QUARTO_VERSION=1.3.340 $0" + echo "" + echo "Options:" + echo " -d, --debug Enable debug output" + echo " -h, --help Print usage and exit" + echo " --prefix Install Quarto to a custom prefix" + echo " Each version of Quarto will have its own subdirectory" + echo " Default: /opt/quarto" +} + + +# Set defaults +PREFIX="/opt/quarto" + +OPTIONS=$(getopt -o hdr: --long help,debug,prefix: -- "$@") +# shellcheck disable=SC2181 +if [[ $? -ne 0 ]]; then + exit 1; +fi + +eval set -- "$OPTIONS" +while true; do + case "$1" in + -d | --debug) + set -x + shift + ;; + -h | --help) + usage + shift + exit + ;; + --prefix) + PREFIX="$2" + shift 2 + ;; + --) shift; + break + ;; + esac +done + +if [ -z "$QUARTO_VERSION" ]; then + usage + exit 1 +fi + +install_quarto() { + # Check if Quarto is already installed + # shellcheck disable=SC2086 + if ${PREFIX}/${QUARTO_VERSION}/bin/quarto --version | grep -qE "^${QUARTO_VERSION}" ; then + echo "$d Quarto $QUARTO_VERSION is already installed in $PREFIX/$QUARTO_VERSION $d" + return + fi + + mkdir -p "/opt/quarto/${QUARTO_VERSION}" + wget -q -O - "https://github.com/quarto-dev/quarto-cli/releases/download/v${QUARTO_VERSION}/quarto-${QUARTO_VERSION}-linux-amd64.tar.gz" | tar xzf - -C "/opt/quarto/${QUARTO_VERSION}" --strip-components=1 +} + +install_quarto diff --git a/product/base/scripts/rhel/install_r.sh b/product/base/scripts/rhel/install_r.sh new file mode 100755 index 00000000..b346ea12 --- /dev/null +++ b/product/base/scripts/rhel/install_r.sh @@ -0,0 +1,173 @@ +#!/bin/bash +set -eo pipefail +export DEBIAN_FRONTEND=noninteractive + +# Output delimiter +d="====" + +usage() { + echo "Usage:" + echo " $0 [OPTIONS]" + echo "" + echo "Examples:" + echo " # Install R version specified by R_VERSION environment variable" + echo " $0" + echo " # Install R 4.1.2" + echo " R_VERSION=4.1.2 $0" + echo " # Install R 4.2.3 and packages listed in /tmp/r_packages.txt" + echo " R_VERSION=4.2.3 $0 -r /tmp/r_packages.txt" + echo "" + echo "Options:" + echo " -d, --debug Enable debug output" + echo " -h, --help Print usage and exit" + echo " --prefix Install R to a custom prefix" + echo " Each version of R will have its own subdirectory" + echo " Default: /opt/R" + echo " --r-exists Expect R version to already be installed" + echo " -r, --requirement " + echo " Install R packages from a requirements file" + echo " --with-source Also download the R source code" +} + + +# Set defaults +if [ -z "${DISTRO}" ]; then + DISTRO=$(lsb_release -is | tr '[:upper:]' '[:lower:]') +fi +if [ -z "${OS_VERSION}" ]; then + OS_VERSION=$(rpm -E %{rhel}) +fi +YUM_ARGS="-y -q" +PREFIX="/opt/R" +R_EXISTS=0 +WITH_SOURCE=0 + +OPTIONS=$(getopt -o hdr: --long help,debug,distro:,prefix:,r-exists,requirement:,with-source -- "$@") +# shellcheck disable=SC2181 +if [[ $? -ne 0 ]]; then + exit 1; +fi + +eval set -- "$OPTIONS" +while true; do + case "$1" in + -d | --debug) + set -x + shift + ;; + -h | --help) + usage + shift + exit + ;; + --prefix) + PREFIX="$2" + shift 2 + ;; + --r-exists) + R_EXISTS=1 + shift + ;; + -r | --requirement) + R_PKG_FILE="$2" + shift 2 + ;; + --with-source) + WITH_SOURCE=1 + shift + ;; + --) shift; + break + ;; + esac +done + +if [ -z "$R_VERSION" ]; then + usage + exit 1 +fi + +# Set R binary path +R_BIN="${PREFIX}/${R_VERSION}/bin/R" + +# Set yum options +YUM_ARGS="-y -q" + +install_r() { + echo "$d$d Installing R $R_VERSION to $PREFIX/$R_VERSION $d$d" + mkdir -p "$PREFIX" + + local r_url="https://cdn.rstudio.com/r/${DISTRO}-${OS_VERSION}/pkgs/R-${R_VERSION}-1-1.x86_64.rpm" + curl -sL "$r_url" -o "/tmp/r-${R_VERSION}.rpm" + + # shellcheck disable=SC2086 + yum install $YUM_ARGS "/tmp/r-${R_VERSION}.rpm" + rm "/tmp/r-${R_VERSION}.rpm" +} + +install_r_dependencies() { + # RHEL installs are more straightforward than Ubuntu. Installing epel-release should cover us well. + local r_deps="epel-release" + + # Check whether dependencies are already installed + # shellcheck disable=2086 + if rpm -q $r_deps >/dev/null 2>&1 ; then + echo "$d R dependencies already installed $d" + return + fi + + echo "$d$d Installng R depencencies $d$d" + + # Install R dependencies + # shellcheck disable=2086 + yum install $YUM_ARGS epel-release +} + +install_r_packages() { + if [ ! -f "$R_PKG_FILE" ]; then + echo "$d R package file $R_PKG_FILE does not exist $d" + exit 1 + fi + + echo "$d$d Installing R-${R_VERSION} packages from ${R_PKG_FILE} $d$d" + local cran_repo="https://packagemanager.rstudio.com/cran/__linux__/${DISTRO}${OS_VERSION}/latest" + + $R_BIN --vanilla --no-echo < /dev/null +install.packages(readLines("$R_PKG_FILE"), repos = "$cran_repo") +EOF + +} + +get_r_source() { + local r_prefix=${R_VERSION:0:1} + local r_source_dir="/opt/r-sources" + local r_source_url="https://cloud.r-project.org/src/base/R-${r_prefix}/R-${R_VERSION}.tar.gz" + + echo "$d Fetching R-${R_VERSION} source code into $r_source_dir $d" + mkdir -p "$r_source_dir" + + curl -sL "$r_source_url" -o "$r_source_dir/R-${R_VERSION}.tar.gz" +} + + +# Only add the dependencies if we don't expect R to exist +if [ "$R_EXISTS" -eq 0 ]; then + install_r_dependencies +fi + +# Check if R is already installed +if $R_BIN --version | grep -qE "^R version ${R_VERSION}" ; then + echo "$d R $R_VERSION is already installed in $PREFIX/$R_VERSION $d" +elif [ "$R_EXISTS" -eq 1 ]; then + echo "$d R $R_VERSION is not installed in $PREFIX/$R_VERSION $d" + exit 1 +else + install_r +fi + +if [ -n "$R_PKG_FILE" ]; then + install_r_packages +fi +if [ "$WITH_SOURCE" -eq 1 ]; then + get_r_source +fi diff --git a/product/base/scripts/rhel/yum.sh b/product/base/scripts/rhel/yum.sh new file mode 100755 index 00000000..af70f94f --- /dev/null +++ b/product/base/scripts/rhel/yum.sh @@ -0,0 +1,112 @@ +#!/bin/bash +set -eo pipefail + +# Output delimiter +d="====" + +usage() { + echo "Usage:" + echo " $0 [OPTIONS] [COMMAND [ARG...]]" + echo "" + echo "Options:" + echo " -d, --debug Enable debug output" + echo " -h, --help Print usage and exit" + echo " --clean Clean yum cache (yum clean all)" + echo " --update Update yum cache (yum check-update)" + echo "" + echo "Commands:" + echo " install Install packages (yum install)" + echo " upgrade Upgrade all packages (yum upgrade)" +} + +# Set defaults +YUM_ARGS="-y -q" +CLEAN=0 +UPDATE=0 + +OPTIONS=$(getopt -o hd --long debug,help,clean,update -- "$@") +if [[ $? -ne 0 ]]; then + exit 1; +fi + +eval set -- "$OPTIONS" +while true; do + case "$1" in + -d | --debug) + set -x + shift + ;; + -h | --help) + usage + shift + exit + ;; + --clean) + CLEAN=1 + shift + ;; + --update) + UPDATE=1 + shift + ;; + --) + shift + break + ;; + *) + echo "Unexpected option: $1" + exit 1 + ;; + esac +done + +# Wait for yum to be done before continuing +# The Deep learning AMI runs an extremely long yum update-install on first boot. +echo "$d Waiting for yum to finish $d" + +# lsof is not installed by default in all images +# We install lsof if it is not already installed, but we don't want the check +# to fail when we invoke this script to install lsof. Chicken & egg problem. +if command -v lsof >/dev/null; then + lsof_result="\$(lsof /var/run/yum.pid)" +else + lsof_result="" +fi +sleep 10 +while [ -n "$lsof_result" ] && [ "$(lslocks | grep "yum")" != "" ]; do + sleep 10 +done + +# Clean yum cache +if [ "$CLEAN" -eq 1 ]; then + echo "$d Cleaning yum cache $d" + yum clean all $YUM_ARGS +fi + +# Update yum cache +if [ "$UPDATE" -eq 1 ]; then + echo "$d Updating yum cache $d" + yum update $YUM_ARGS +fi + +case "$1" in + install) + shift + echo "$d$d Installing yum packages $d$d" + # shellcheck disable=SC2086 + yum install $YUM_ARGS "$@" + ;; + upgrade) + echo "$d$d Upgrading yum packages $d$d" + # shellcheck disable=SC2086 + yum upgrade $YUM_ARGS + ;; + *) + # Allow clean, update to be used as commands + if [ "$UPDATE" -eq 1 ] || [ "$CLEAN" -eq 1 ]; then + exit 0 + fi + usage + exit 1 + ;; +esac diff --git a/product/base/scripts/ubuntu/apt.sh b/product/base/scripts/ubuntu/apt.sh new file mode 100755 index 00000000..e67877d6 --- /dev/null +++ b/product/base/scripts/ubuntu/apt.sh @@ -0,0 +1,118 @@ +#!/bin/bash +set -eo pipefail +export DEBIAN_FRONTEND=noninteractive + +# Output delimiter +d="====" + +usage() { + echo "Usage:" + echo " $0 [OPTIONS] [COMMAND [ARG...]]" + echo "" + echo "Options:" + echo " -d, --debug Enable debug output" + echo " -h, --help Print usage and exit" + echo " --clean Clean apt cache (apt-get clean)" + echo " --update Update apt cache (apt-get update)" + echo "" + echo "Commands:" + echo " install Install packages (apt-get install)" + echo " upgrade Upgrade all packages (apt-get upgrade)" +} + +# Set defaults +APT_ARGS="-o DPkg::Lock::Timeout=60 -y -qq" +CLEAN=0 +UPDATE=0 + +OPTIONS=$(getopt -o hd --long debug,help,clean,update -- "$@") +if [[ $? -ne 0 ]]; then + exit 1; +fi + +eval set -- "$OPTIONS" +while true; do + case "$1" in + -d | --debug) + set -x + shift + ;; + -h | --help) + usage + shift + exit + ;; + --clean) + CLEAN=1 + shift + ;; + --update) + UPDATE=1 + shift + ;; + --) + shift + break + ;; + *) + echo "Unexpected option: $1" + exit 1 + ;; + esac +done + +# Wait for apt to be done before continuing +# The Deep learning AMI runs an extremely long apt update-install on first boot. +echo "$d Waiting for apt to finish $d" + +# lsof is not installed by default in all images +# We install lsof if it is not already installed, but we don't want the check +# to fail when we invoke this script to install lsof. Chicken & egg problem. +if command -v lsof >/dev/null; then + lsof_result="\$(lsof /var/lib/apt/lists/lock)" +else + lsof_result="" +fi +sleep 10 +while [ -n "$lsof_result" ] && [ "$(lslocks | grep "apt")" != "" ]; do + sleep 10 +done + +# Clean apt cache +if [ "$CLEAN" -eq 1 ]; then + echo "$d Cleaning apt cache $d" + # shellcheck disable=SC2086 + apt-get clean $APT_ARGS + rm -rf /var/lib/apt/lists/* +fi + +# Update apt cache +if [ "$UPDATE" -eq 1 ]; then + echo "$d Updating apt cache $d" + # shellcheck disable=SC2086 + apt-get update --fix-missing $APT_ARGS +fi + +case "$1" in + install) + shift + echo "$d$d Installing apt packages $d$d" + # shellcheck disable=SC2086 + apt-get install $APT_ARGS "$@" + ;; + upgrade) + echo "$d$d Upgrading apt packages $d$d" + # shellcheck disable=SC2086 + apt-get upgrade $APT_ARGS + # shellcheck disable=SC2086 + apt-get dist-upgrade $APT_ARGS + ;; + *) + # Allow clean, update to be used as commands + if [ "$UPDATE" -eq 1 ] || [ "$CLEAN" -eq 1 ]; then + exit 0 + fi + usage + exit 1 + ;; +esac diff --git a/product/base/scripts/ubuntu/install_drivers.sh b/product/base/scripts/ubuntu/install_drivers.sh new file mode 100755 index 00000000..68d332d9 --- /dev/null +++ b/product/base/scripts/ubuntu/install_drivers.sh @@ -0,0 +1,21 @@ +#!/bin/bash +set -eo pipefail +export DEBIAN_FRONTEND=noninteractive + +# Output delimiter +d="====" + +if [ -z "$DRIVERS_VERSION" ]; then + echo "$d No DRIVERS_VERSION specified $d" + exit 1 +fi + +echo "$d$d Installing Professional Drivers ${DRIVERS_VERSION} $d$d" + +drivers_url="https://cdn.rstudio.com/drivers/7C152C12/installer/rstudio-drivers_${DRIVERS_VERSION}_amd64.deb" +curl -sL "$drivers_url" -o "/tmp/rstudio-drivers_${DRIVERS_VERSION}_amd64.deb" + +apt-get install -y -qq "/tmp/rstudio-drivers_${DRIVERS_VERSION}_amd64.deb" +cat /opt/rstudio-drivers/odbcinst.ini.sample > /etc/odbcinst.ini + +rm /tmp/rstudio-drivers_${DRIVERS_VERSION}_amd64.deb diff --git a/product/base/scripts/ubuntu/install_python.sh b/product/base/scripts/ubuntu/install_python.sh new file mode 100755 index 00000000..06b6e12c --- /dev/null +++ b/product/base/scripts/ubuntu/install_python.sh @@ -0,0 +1,115 @@ +#!/bin/bash +set -eo pipefail +export DEBIAN_FRONTEND=noninteractive + +# Output delimiter +d="====" + +usage() { + echo "Usage:" + echo " $0 [OPTIONS]" + echo "" + echo "Examples:" + echo " # Install Python version specified by PYTHON_VERSION environment variable" + echo " $0" + echo " # Install Python 3.10.4" + echo " PYTHON_VERSION=3.10.4 $0" + echo " # Install Python and packages listed in /tmp/pythonh_packages.txt" + echo " PYTHON_VERSION=3.11.1 $0 -r /tmp/r_packages.txt" + echo "" + echo "Options:" + echo " -d, --debug Enable debug output" + echo " -h, --help Print usage and exit" + echo " --prefix Install Python to a custom prefix" + echo " Each version of Python will have its own subdirectory" + echo " Default: /opt/python" + echo " -r, --requirement " + echo " Install python packages from a requirements file" +} + + +# Set defaults +APT_ARGS="-o DPkg::Lock::Timeout=60 -y -qq" +PREFIX="/opt/python" + +OPTIONS=$(getopt -o hdr: --long help,debug,prefix:,requirement: -- "$@") +# shellcheck disable=SC2181 +if [[ $? -ne 0 ]]; then + exit 1; +fi + +eval set -- "$OPTIONS" +while true; do + case "$1" in + -d | --debug) + set -x + shift + ;; + -h | --help) + usage + shift + exit + ;; + --prefix) + PREFIX="$2" + shift 2 + ;; + -r | --requirement) + PYTHON_PKG_FILE="$2" + shift 2 + ;; + --) shift; + break + ;; + esac +done + +if [ -z "$PYTHON_VERSION" ]; then + usage + exit 1 +fi + +# Set python binary path +PYTHON_BIN="${PREFIX}/${PYTHON_VERSION}/bin/python" + +# Set apt options +APT_ARGS="-o DPkg::Lock::Timeout=60 -y -qq" + +# Set ubuntu version +UBUNTU_VERSION=$(lsb_release -rs) + +install_python() { + # Check if Python is already installed + if $PYTHON_BIN --version | grep -qE "^Python ${PYTHON_VERSION}" ; then + echo "$d Python $PYTHON_VERSION is already installed in $PREFIX/$PYTHON_VERSION $d" + return + fi + + echo "$d$d Installing Python $PYTHON_VERSION to $PREFIX/$PYTHON_VERSION $d$d" + mkdir -p "$PREFIX" + + local python_url="https://cdn.rstudio.com/python/ubuntu-${UBUNTU_VERSION//./}/pkgs/python-${PYTHON_VERSION}_1_amd64.deb" + curl -sL "$python_url" -o "/tmp/python-${PYTHON_VERSION}.deb" + + # shellcheck disable=SC2086 + apt-get install $APT_ARGS "/tmp/python-${PYTHON_VERSION}.deb" + rm "/tmp/python-${PYTHON_VERSION}.deb" + # Upgrade pip to latest version + $PYTHON_BIN -m pip install -U pip +} + +install_python_packages() { + if [ ! -f "$PYTHON_PKG_FILE" ]; then + echo "$d Python package file $PYTHON_PKG_FILE does not exist $d" + exit 1 + fi + + echo "$d$d Installing python-${PYTHON_VERSION} packages from ${PYTHON_PKG_FILE} $d$d" + $PYTHON_BIN -m pip install -U pip + $PYTHON_BIN -m pip install -r "$PYTHON_PKG_FILE" +} + +install_python +if [ -n "$PYTHON_PKG_FILE" ]; then + install_python_packages +fi diff --git a/product/base/scripts/ubuntu/install_quarto.sh b/product/base/scripts/ubuntu/install_quarto.sh new file mode 100755 index 00000000..e6071b13 --- /dev/null +++ b/product/base/scripts/ubuntu/install_quarto.sh @@ -0,0 +1,75 @@ +#!/bin/bash +set -eo pipefail +export DEBIAN_FRONTEND=noninteractive + +# Output delimiter +d="====" + +usage() { + echo "Usage:" + echo " $0 [OPTIONS]" + echo "" + echo "Examples:" + echo " # Install Quarto version specified by QUARTO_VERSION environment variable" + echo " $0" + echo " # Install Quarto 1.3.340" + echo " QUARTO_VERSION=1.3.340 $0" + echo "" + echo "Options:" + echo " -d, --debug Enable debug output" + echo " -h, --help Print usage and exit" + echo " --prefix Install Quarto to a custom prefix" + echo " Each version of Quarto will have its own subdirectory" + echo " Default: /opt/quarto" +} + + +# Set defaults +PREFIX="/opt/quarto" + +OPTIONS=$(getopt -o hdr: --long help,debug,prefix: -- "$@") +# shellcheck disable=SC2181 +if [[ $? -ne 0 ]]; then + exit 1; +fi + +eval set -- "$OPTIONS" +while true; do + case "$1" in + -d | --debug) + set -x + shift + ;; + -h | --help) + usage + shift + exit + ;; + --prefix) + PREFIX="$2" + shift 2 + ;; + --) shift; + break + ;; + esac +done + +if [ -z "$QUARTO_VERSION" ]; then + usage + exit 1 +fi + +install_quarto() { + # Check if Quarto is already installed + # shellcheck disable=SC2086 + if ${PREFIX}/${QUARTO_VERSION}/bin/quarto --version | grep -qE "^${QUARTO_VERSION}" ; then + echo "$d Quarto $QUARTO_VERSION is already installed in $PREFIX/$QUARTO_VERSION $d" + return + fi + + mkdir -p "/opt/quarto/${QUARTO_VERSION}" + wget -q -O - "https://github.com/quarto-dev/quarto-cli/releases/download/v${QUARTO_VERSION}/quarto-${QUARTO_VERSION}-linux-amd64.tar.gz" | tar xzf - -C "/opt/quarto/${QUARTO_VERSION}" --strip-components=1 +} + +install_quarto diff --git a/product/base/scripts/ubuntu/install_r.sh b/product/base/scripts/ubuntu/install_r.sh new file mode 100755 index 00000000..67914952 --- /dev/null +++ b/product/base/scripts/ubuntu/install_r.sh @@ -0,0 +1,208 @@ +#!/bin/bash +set -eo pipefail +export DEBIAN_FRONTEND=noninteractive + +# Output delimiter +d="====" + +usage() { + echo "Usage:" + echo " $0 [OPTIONS]" + echo "" + echo "Examples:" + echo " # Install R version specified by R_VERSION environment variable" + echo " $0" + echo " # Install R 4.1.2" + echo " R_VERSION=4.1.2 $0" + echo " # Install R 4.2.3 and packages listed in /tmp/r_packages.txt" + echo " R_VERSION=4.2.3 $0 -r /tmp/r_packages.txt" + echo "" + echo "Options:" + echo " -d, --debug Enable debug output" + echo " -h, --help Print usage and exit" + echo " --prefix Install R to a custom prefix" + echo " Each version of R will have its own subdirectory" + echo " Default: /opt/R" + echo " --r-exists Expect R version to already be installed" + echo " -r, --requirement " + echo " Install R packages from a requirements file" + echo " --with-source Also download the R source code" +} + + +# Set defaults +APT_ARGS="-o DPkg::Lock::Timeout=60 -y -qq" +PREFIX="/opt/R" +R_EXISTS=0 +WITH_SOURCE=0 + +OPTIONS=$(getopt -o hdr: --long help,debug,distro:,prefix:,r-exists,requirement:,with-source -- "$@") +# shellcheck disable=SC2181 +if [[ $? -ne 0 ]]; then + exit 1; +fi + +eval set -- "$OPTIONS" +while true; do + case "$1" in + -d | --debug) + set -x + shift + ;; + -h | --help) + usage + shift + exit + ;; + --prefix) + PREFIX="$2" + shift 2 + ;; + --r-exists) + R_EXISTS=1 + shift + ;; + -r | --requirement) + R_PKG_FILE="$2" + shift 2 + ;; + --with-source) + WITH_SOURCE=1 + shift + ;; + --) shift; + break + ;; + esac +done + +if [ -z "$R_VERSION" ]; then + usage + exit 1 +fi + +# Set R binary path +R_BIN="${PREFIX}/${R_VERSION}/bin/R" + +# Set apt options +APT_ARGS="-o DPkg::Lock::Timeout=60 -y -qq" +APT_KEY="0x51716619e084dab9" +APT_KEY_FILE="/usr/share/keyrings/cran-rstudio-keyring.gpg" +APT_FILE="/etc/apt/sources.list.d/cran-rstudio.list" + +UBUNTU_CODENAME=$(lsb_release -cs) +UBUNTU_VERSION=$(lsb_release -rs) + +add_cran_apt_source() { + # Ensure we have gnupg2 & dirmngr installed + # shellcheck disable=SC2086 + apt-get install $APT_ARGS --install-recommends gnupg2 dirmngr + # Create ~/.gnupg and start dirmngr in the background + gpg --list-keys >/dev/null 2>&1 + eval "$(dirmngr --daemon)" + + # Add the apt-key to the keyring + gpg --no-default-keyring --keyring $APT_KEY_FILE --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys $APT_KEY + kill "$(echo "$DIRMNGR_INFO" | cut -d: -f2)" + + echo "deb [signed-by=${APT_KEY_FILE}] https://cran.rstudio.com/bin/linux/ubuntu ${UBUNTU_CODENAME}-cran40/" >> $APT_FILE + echo "deb-src [signed-by=${APT_KEY_FILE}] https://cran.rstudio.com/bin/linux/ubuntu ${UBUNTU_CODENAME}-cran40/" >> $APT_FILE + + # shellcheck disable=SC2086 + apt-get update $APT_ARGS +} + +remove_cran_apt_source() { + rm -f $APT_FILE $APT_KEY_FILE + # shellcheck disable=SC2086 + apt-get update $APT_ARGS +} + +install_r() { + echo "$d$d Installing R $R_VERSION to $PREFIX/$R_VERSION $d$d" + mkdir -p "$PREFIX" + + local r_url="https://cdn.rstudio.com/r/ubuntu-${UBUNTU_VERSION//./}/pkgs/r-${R_VERSION}_1_amd64.deb" + curl -sL "$r_url" -o "/tmp/r-${R_VERSION}.deb" + + # shellcheck disable=SC2086 + apt-get install $APT_ARGS "/tmp/r-${R_VERSION}.deb" + rm "/tmp/r-${R_VERSION}.deb" +} + +install_r_dependencies() { + # There are many dependencies that R users may rely on that we want to + # include in the images. These include things like a functional X server, + # fonts, and other libraries that are commonly used by R packages. + local r_deps="r-base-core r-base-dev" + + # Check whether dependencies are already installed + # shellcheck disable=2086 + if dpkg -s $r_deps >/dev/null 2>&1 ; then + echo "$d R dependencies already installed $d" + return + fi + + echo "$d$d Installng R depencencies $d$d" + # Ensure we have apt-transport-https installed + # shellcheck disable=SC2086 + apt-get install $APT_ARGS apt-transport-https + + # Install R dependencies + # shellcheck disable=2086 + apt-get install $APT_ARGS $r_deps +} + +install_r_packages() { + if [ ! -f "$R_PKG_FILE" ]; then + echo "$d R package file $R_PKG_FILE does not exist $d" + exit 1 + fi + + echo "$d$d Installing R-${R_VERSION} packages from ${R_PKG_FILE} $d$d" + local cran_repo="https://packagemanager.rstudio.com/cran/__linux__/${UBUNTU_CODENAME}/latest" + + $R_BIN --vanilla --no-echo < /dev/null +install.packages(readLines("$R_PKG_FILE"), repos = "$cran_repo") +EOF + +} + +get_r_source() { + local r_prefix=${R_VERSION:0:1} + local r_source_dir="/opt/r-sources" + local r_source_url="https://cloud.r-project.org/src/base/R-${r_prefix}/R-${R_VERSION}.tar.gz" + + echo "$d Fetching R-${R_VERSION} source code into $r_source_dir $d" + mkdir -p "$r_source_dir" + + curl -sL "$r_source_url" -o "$r_source_dir/R-${R_VERSION}.tar.gz" +} + + +# Only add the CRAN apt source & dependencies if we don't expect R to exist +if [ "$R_EXISTS" -eq 0 ]; then + add_cran_apt_source + install_r_dependencies +fi + +# Check if R is already installed +if $R_BIN --version | grep -qE "^R version ${R_VERSION}" ; then + echo "$d R $R_VERSION is already installed in $PREFIX/$R_VERSION $d" +elif [ "$R_EXISTS" -eq 1 ]; then + echo "$d R $R_VERSION is not installed in $PREFIX/$R_VERSION $d" + exit 1 +else + install_r +fi + +if [ -n "$R_PKG_FILE" ]; then + install_r_packages +fi +if [ "$WITH_SOURCE" -eq 1 ]; then + get_r_source +fi + +if [ "$R_EXISTS" -eq 0 ]; then + remove_cran_apt_source +fi diff --git a/product/base/test/goss.yaml b/product/base/test/goss.yaml index 18e338a5..e321ebe0 100644 --- a/product/base/test/goss.yaml +++ b/product/base/test/goss.yaml @@ -15,6 +15,28 @@ package: {{end}} file: + {{if .Env.OS | regexMatch "ubuntu.*"}} + /opt/positscripts/apt.sh: + exists: true + mode: "0755" + {{end}} + {{if .Env.OS | regexMatch "centos.*"}} + /opt/positscripts/yum.sh: + exists: true + mode: "0755" + {{end}} + /opt/positscripts/install_drivers.sh: + exists: true + mode: "0755" + /opt/positscripts/install_python.sh: + exists: true + mode: "0755" + /opt/positscripts/install_quarto.sh: + exists: true + mode: "0755" + /opt/positscripts/install_r.sh: + exists: true + mode: "0755" /opt/R/{{.Env.R_VERSION}}/bin/R: exists: true /opt/R/{{.Env.R_VERSION_ALT}}/bin/R: diff --git a/product/pro/Dockerfile.centos7 b/product/pro/Dockerfile.centos7 index 936611e8..254456dc 100644 --- a/product/pro/Dockerfile.centos7 +++ b/product/pro/Dockerfile.centos7 @@ -6,14 +6,15 @@ ARG PYTHON_VERSION=3.9.14 ARG PYTHON_VERSION_ALT=3.8.15 ARG DRIVERS_VERSION=2024.03.0-1 -RUN yum update -y \ - && yum install -y unixODBC unixODBC-devel \ - && curl -O https://cdn.rstudio.com/drivers/7C152C12/installer/rstudio-drivers-${DRIVERS_VERSION}.el.x86_64.rpm \ - && yum install -y ./rstudio-drivers-${DRIVERS_VERSION}.el.x86_64.rpm \ - && yum clean all \ - && rm -f rstudio-drivers-${DRIVERS_VERSION}.el.x86_64.rpm \ - && cp /opt/rstudio-drivers/odbcinst.ini.sample /etc/odbcinst.ini \ - && "/opt/R/${R_VERSION}/bin/R" -e 'install.packages("odbc", repos="https://packagemanager.rstudio.com/cran/__linux__/centos7/latest")' +ARG SCRIPTS_DIR=/opt/positscripts + +COPY deps/r_packages.txt /tmp/r_packages.txt +RUN ${SCRIPTS_DIR}/yum.sh --update upgrade \ + && ${SCRIPTS_DIR}/yum.sh install unixODBC unixODBC-devel \ + && DRIVERS_VERSION=${DRIVERS_VERSION} ${SCRIPTS_DIR}/install_drivers.sh \ + && ${SCRIPTS_DIR}/yum.sh --clean \ + && R_VERSION=${R_VERSION} ${SCRIPTS_DIR}/install_r.sh -r /tmp/r_packages.txt \ + && rm -f /tmp/r_packages.txt LABEL rstudio.pro-drivers.version="${DRIVERS_VERSION}" diff --git a/product/pro/Dockerfile.ubuntu2204 b/product/pro/Dockerfile.ubuntu2204 index f17dbfc2..7e36f856 100644 --- a/product/pro/Dockerfile.ubuntu2204 +++ b/product/pro/Dockerfile.ubuntu2204 @@ -7,16 +7,16 @@ ARG PYTHON_VERSION=3.9.17 ARG PYTHON_VERSION_ALT=3.8.17 ARG DRIVERS_VERSION=2024.03.0 -RUN apt-get update \ - && apt-get install -yq --no-install-recommends unixodbc unixodbc-dev \ - && curl -O https://cdn.rstudio.com/drivers/7C152C12/installer/rstudio-drivers_${DRIVERS_VERSION}_amd64.deb \ - && apt-get update \ - && apt-get install -yq --no-install-recommends ./rstudio-drivers_${DRIVERS_VERSION}_amd64.deb \ - && rm -f ./rstudio-drivers_${DRIVERS_VERSION}_amd64.deb \ - && rm -rf /var/lib/apt/lists/* \ - && cp /opt/rstudio-drivers/odbcinst.ini.sample /etc/odbcinst.ini \ - && /opt/R/${R_VERSION}/bin/R -e 'install.packages("odbc", repos="https://packagemanager.rstudio.com/cran/__linux__/jammy/latest")' +ARG SCRIPTS_DIR=/opt/positscripts -LABEL rstudio.pro-drivers.version="${DRIVERS_VERSION}" +COPY deps/r_packages.txt /tmp/r_packages.txt +RUN ${SCRIPTS_DIR}/apt.sh --update upgrade \ + && ${SCRIPTS_DIR}/apt.sh install unixodbc unixodbc-dev \ + && DRIVERS_VERSION=${DRIVERS_VERSION} ${SCRIPTS_DIR}/install_drivers.sh \ + && ${SCRIPTS_DIR}/apt.sh --clean \ + && R_VERSION=${R_VERSION} ${SCRIPTS_DIR}/install_r.sh -r /tmp/r_packages.txt \ + && rm -f /tmp/r_packages.txt + +LABEL posit.pro-drivers.version="${DRIVERS_VERSION}" ENTRYPOINT ["/tini", "--"] diff --git a/product/pro/deps/r_packages.txt b/product/pro/deps/r_packages.txt new file mode 100644 index 00000000..47869868 --- /dev/null +++ b/product/pro/deps/r_packages.txt @@ -0,0 +1 @@ +odbc \ No newline at end of file