diff --git a/.devcontainer/.devpod-internal/0/NOTES.md b/.devcontainer/.devpod-internal/0/NOTES.md new file mode 100644 index 0000000..f2c7aa7 --- /dev/null +++ b/.devcontainer/.devpod-internal/0/NOTES.md @@ -0,0 +1,26 @@ +## OS Support + +This Feature should work on recent versions of Debian/Ubuntu, RedHat Enterprise Linux, Fedora, RockyLinux, and Alpine Linux. + +## Using with dev container images + +This Feature is used in many of the [dev container images](https://github.com/search?q=repo%3Adevcontainers%2Fimages+%22ghcr.io%2Fdevcontainers%2Ffeatures%2Fcommon-utils%22&type=code), as a result +these images have already allocated UID & GID 1000. Attempting to add this Feature with UID 1000 and/or GID 1000 on top of such a dev container image will result in an error when building the dev container. + +## Customizing the command prompt + +By default, this script provides a custom command prompt that includes information about the git repository for the current folder. However, with certain large repositories, this can result in a slow command prompt due to the performance of needed git operations. + +For performance reasons, a "dirty" indicator that tells you whether or not there are uncommitted changes is disabled by default. You can opt to turn this on for smaller repositories by entering the following in a terminal or adding it to your `postCreateCommand`: + +```bash +git config devcontainers-theme.show-dirty 1 +``` + +To completely disable the git portion of the prompt for the current folder's repository, you can use this configuration setting instead: + +```bash +git config devcontainers-theme.hide-status 1 +``` + +For `zsh`, the default theme is a [standard Oh My Zsh! theme](https://ohmyz.sh/). You may pick a different one by modifying the `ZSH_THEME` variable in `~/.zshrc`. diff --git a/.devcontainer/.devpod-internal/0/README.md b/.devcontainer/.devpod-internal/0/README.md new file mode 100644 index 0000000..b8e37a8 --- /dev/null +++ b/.devcontainer/.devpod-internal/0/README.md @@ -0,0 +1,58 @@ + +# Common Utilities (common-utils) + +Installs a set of common command line utilities, Oh My Zsh!, and sets up a non-root user. + +## Example Usage + +```json +"features": { + "ghcr.io/devcontainers/features/common-utils:2": {} +} +``` + +## Options + +| Options Id | Description | Type | Default Value | +|-----|-----|-----|-----| +| installZsh | Install ZSH? | boolean | true | +| configureZshAsDefaultShell | Change default shell to ZSH? | boolean | false | +| installOhMyZsh | Install Oh My Zsh!? | boolean | true | +| installOhMyZshConfig | Allow installing the default dev container .zshrc templates? | boolean | true | +| upgradePackages | Upgrade OS packages? | boolean | true | +| username | Enter name of a non-root user to configure or none to skip | string | automatic | +| userUid | Enter UID for non-root user | string | automatic | +| userGid | Enter GID for non-root user | string | automatic | +| nonFreePackages | Add packages from non-free Debian repository? (Debian only) | boolean | false | + +## OS Support + +This Feature should work on recent versions of Debian/Ubuntu, RedHat Enterprise Linux, Fedora, RockyLinux, and Alpine Linux. + +## Using with dev container images + +This Feature is used in many of the [dev container images](https://github.com/search?q=repo%3Adevcontainers%2Fimages+%22ghcr.io%2Fdevcontainers%2Ffeatures%2Fcommon-utils%22&type=code), as a result +these images have already allocated UID & GID 1000. Attempting to add this Feature with UID 1000 and/or GID 1000 on top of such a dev container image will result in an error when building the dev container. + +## Customizing the command prompt + +By default, this script provides a custom command prompt that includes information about the git repository for the current folder. However, with certain large repositories, this can result in a slow command prompt due to the performance of needed git operations. + +For performance reasons, a "dirty" indicator that tells you whether or not there are uncommitted changes is disabled by default. You can opt to turn this on for smaller repositories by entering the following in a terminal or adding it to your `postCreateCommand`: + +```bash +git config devcontainers-theme.show-dirty 1 +``` + +To completely disable the git portion of the prompt for the current folder's repository, you can use this configuration setting instead: + +```bash +git config devcontainers-theme.hide-status 1 +``` + +For `zsh`, the default theme is a [standard Oh My Zsh! theme](https://ohmyz.sh/). You may pick a different one by modifying the `ZSH_THEME` variable in `~/.zshrc`. + + +--- + +_Note: This file was auto-generated from the [devcontainer-feature.json](https://github.com/devcontainers/features/blob/main/src/common-utils/devcontainer-feature.json). Add additional notes to a `NOTES.md`._ diff --git a/.devcontainer/.devpod-internal/0/bin/code b/.devcontainer/.devpod-internal/0/bin/code new file mode 100755 index 0000000..b0d517f --- /dev/null +++ b/.devcontainer/.devpod-internal/0/bin/code @@ -0,0 +1,16 @@ +#!/bin/sh + +get_in_path_except_current() { + which -a "$1" | grep -A1 "$0" | grep -v "$0" +} + +code="$(get_in_path_except_current code)" + +if [ -n "$code" ]; then + exec "$code" "$@" +elif [ "$(command -v code-insiders)" ]; then + exec code-insiders "$@" +else + echo "code or code-insiders is not installed" >&2 + exit 127 +fi diff --git a/.devcontainer/.devpod-internal/0/bin/devcontainer-info b/.devcontainer/.devpod-internal/0/bin/devcontainer-info new file mode 100755 index 0000000..abbb682 --- /dev/null +++ b/.devcontainer/.devpod-internal/0/bin/devcontainer-info @@ -0,0 +1,35 @@ +#!/bin/sh + +# Load meta.env +if [ -f "/usr/local/etc/vscode-dev-containers/meta.env" ]; then + . /usr/local/etc/vscode-dev-containers/meta.env +fi +if [ -f "/usr/local/etc/dev-containers/meta.env" ]; then + . /usr/local/etc/dev-containers/meta.env +fi + +# Minimal output +if [ "$1" = "version" ] || [ "$1" = "image-version" ]; then + echo "${VERSION}" + exit 0 +elif [ "$1" = "release" ]; then + echo "${GIT_REPOSITORY_RELEASE}" + exit 0 +elif [ "$1" = "content" ] || [ "$1" = "content-url" ] || [ "$1" = "contents" ] || [ "$1" = "contents-url" ]; then + echo "${CONTENTS_URL}" + exit 0 +fi + +#Full output +echo +echo "Development container image information" +echo +if [ ! -z "${VERSION}" ]; then echo "- Image version: ${VERSION}"; fi +if [ ! -z "${DEFINITION_ID}" ]; then echo "- Definition ID: ${DEFINITION_ID}"; fi +if [ ! -z "${VARIANT}" ]; then echo "- Variant: ${VARIANT}"; fi +if [ ! -z "${GIT_REPOSITORY}" ]; then echo "- Source code repository: ${GIT_REPOSITORY}"; fi +if [ ! -z "${GIT_REPOSITORY_RELEASE}" ]; then echo "- Source code release/branch: ${GIT_REPOSITORY_RELEASE}"; fi +if [ ! -z "${GIT_REPOSITORY_REVISION}" ]; then echo "- Source code revision: ${GIT_REPOSITORY_REVISION}"; fi +if [ ! -z "${BUILD_TIMESTAMP}" ]; then echo "- Timestamp: ${BUILD_TIMESTAMP}"; fi +if [ ! -z "${CONTENTS_URL}" ]; then echo && echo "More info: ${CONTENTS_URL}"; fi +echo diff --git a/.devcontainer/.devpod-internal/0/bin/systemctl b/.devcontainer/.devpod-internal/0/bin/systemctl new file mode 100755 index 0000000..4ead985 --- /dev/null +++ b/.devcontainer/.devpod-internal/0/bin/systemctl @@ -0,0 +1,7 @@ +#!/bin/sh +set -e +if [ -d "/run/systemd/system" ]; then + exec /bin/systemctl "$@" +else + echo '\n"systemd" is not running in this container due to its overhead.\nUse the "service" command to start services instead. e.g.: \n\nservice --status-all' +fi diff --git a/.devcontainer/.devpod-internal/0/devcontainer-feature.json b/.devcontainer/.devpod-internal/0/devcontainer-feature.json new file mode 100644 index 0000000..dc54e69 --- /dev/null +++ b/.devcontainer/.devpod-internal/0/devcontainer-feature.json @@ -0,0 +1,69 @@ +{ + "id": "common-utils", + "version": "2.3.0", + "name": "Common Utilities", + "documentationURL": "https://github.com/devcontainers/features/tree/main/src/common-utils", + "description": "Installs a set of common command line utilities, Oh My Zsh!, and sets up a non-root user.", + "options": { + "installZsh": { + "type": "boolean", + "default": true, + "description": "Install ZSH?" + }, + "configureZshAsDefaultShell": { + "type": "boolean", + "default": false, + "description": "Change default shell to ZSH?" + }, + "installOhMyZsh": { + "type": "boolean", + "default": true, + "description": "Install Oh My Zsh!?" + }, + "installOhMyZshConfig": { + "type": "boolean", + "default": true, + "description": "Allow installing the default dev container .zshrc templates?" + }, + "upgradePackages": { + "type": "boolean", + "default": true, + "description": "Upgrade OS packages?" + }, + "username": { + "type": "string", + "proposals": [ + "devcontainer", + "vscode", + "codespace", + "none", + "automatic" + ], + "default": "automatic", + "description": "Enter name of a non-root user to configure or none to skip" + }, + "userUid": { + "type": "string", + "proposals": [ + "1001", + "automatic" + ], + "default": "automatic", + "description": "Enter UID for non-root user" + }, + "userGid": { + "type": "string", + "proposals": [ + "1001", + "automatic" + ], + "default": "automatic", + "description": "Enter GID for non-root user" + }, + "nonFreePackages": { + "type": "boolean", + "default": false, + "description": "Add packages from non-free Debian repository? (Debian only)" + } + } +} diff --git a/.devcontainer/.devpod-internal/0/devcontainer-features-install.sh b/.devcontainer/.devpod-internal/0/devcontainer-features-install.sh new file mode 100644 index 0000000..5015072 --- /dev/null +++ b/.devcontainer/.devpod-internal/0/devcontainer-features-install.sh @@ -0,0 +1,38 @@ +#!/bin/sh +set -e + +on_exit () { + [ $? -eq 0 ] && exit + echo 'ERROR: Feature "Common Utilities" (ghcr.io/devcontainers/features/common-utils) failed to install! Look at the documentation at ${documentation} for help troubleshooting this error.' +} + +trap on_exit EXIT + +set -a +. ../devcontainer-features.builtin.env +. ./devcontainer-features.env +set +a + +echo =========================================================================== + +echo 'Feature : Common Utilities' +echo 'Description : Installs a set of common command line utilities, Oh My Zsh!, and sets up a non-root user.' +echo 'Id : ghcr.io/devcontainers/features/common-utils' +echo 'Version : 2.3.0' +echo 'Documentation : https://github.com/devcontainers/features/tree/main/src/common-utils' +echo 'Options :' +echo ' INSTALLZSH="true" + CONFIGUREZSHASDEFAULTSHELL="true" + USERUID="automatic" + INSTALLOHMYZSHCONFIG="true" + UPGRADEPACKAGES="true" + USERNAME="automatic" + NONFREEPACKAGES="false" + INSTALLOHMYZSH="false" + USERGID="automatic"' +echo 'Environment :' +printenv +echo =========================================================================== + +chmod +x ./install.sh +./install.sh diff --git a/.devcontainer/.devpod-internal/0/devcontainer-features.env b/.devcontainer/.devpod-internal/0/devcontainer-features.env new file mode 100644 index 0000000..f8358e0 --- /dev/null +++ b/.devcontainer/.devpod-internal/0/devcontainer-features.env @@ -0,0 +1,9 @@ +INSTALLZSH="true" +CONFIGUREZSHASDEFAULTSHELL="true" +USERUID="automatic" +INSTALLOHMYZSHCONFIG="true" +UPGRADEPACKAGES="true" +USERNAME="automatic" +NONFREEPACKAGES="false" +INSTALLOHMYZSH="false" +USERGID="automatic" \ No newline at end of file diff --git a/.devcontainer/.devpod-internal/0/install.sh b/.devcontainer/.devpod-internal/0/install.sh new file mode 100755 index 0000000..8f1ece4 --- /dev/null +++ b/.devcontainer/.devpod-internal/0/install.sh @@ -0,0 +1,36 @@ +#!/bin/sh +#------------------------------------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See https://github.com/devcontainers/features/blob/main/LICENSE for license information. +#------------------------------------------------------------------------------------------------------------------------- +# +# Docs: https://github.com/devcontainers/features/tree/main/src/common-utils +# Maintainer: The Dev Container spec maintainers + +set -e + +INSTALL_ZSH="${INSTALLZSH:-"true"}" +CONFIGURE_ZSH_AS_DEFAULT_SHELL="${CONFIGUREZSHASDEFAULTSHELL:-"false"}" +INSTALL_OH_MY_ZSH="${INSTALLOHMYZSH:-"true"}" +INSTALL_OH_MY_ZSH_CONFIG="${INSTALLOHMYZSHCONFIG:-"true"}" +UPGRADE_PACKAGES="${UPGRADEPACKAGES:-"true"}" +USERNAME="${USERNAME:-"automatic"}" +USER_UID="${UID:-"automatic"}" +USER_GID="${GID:-"automatic"}" +ADD_NON_FREE_PACKAGES="${NONFREEPACKAGES:-"false"}" + +MARKER_FILE="/usr/local/etc/vscode-dev-containers/common" + +if [ "$(id -u)" -ne 0 ]; then + echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.' + exit 1 +fi + +# If we're using Alpine, install bash before executing +. /etc/os-release +if [ "${ID}" = "alpine" ]; then + apk add --no-cache bash +fi + +exec /bin/bash "$(dirname $0)/main.sh" "$@" +exit $? diff --git a/.devcontainer/.devpod-internal/0/main.sh b/.devcontainer/.devpod-internal/0/main.sh new file mode 100644 index 0000000..d1a977f --- /dev/null +++ b/.devcontainer/.devpod-internal/0/main.sh @@ -0,0 +1,569 @@ +#!/bin/bash +#------------------------------------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See https://github.com/devcontainers/features/blob/main/LICENSE for license information. +#------------------------------------------------------------------------------------------------------------------------- +# +# Docs: https://github.com/devcontainers/features/tree/main/src/common-utils +# Maintainer: The Dev Container spec maintainers + +set -e + +INSTALL_ZSH="${INSTALLZSH:-"true"}" +CONFIGURE_ZSH_AS_DEFAULT_SHELL="${CONFIGUREZSHASDEFAULTSHELL:-"false"}" +INSTALL_OH_MY_ZSH="${INSTALLOHMYZSH:-"true"}" +INSTALL_OH_MY_ZSH_CONFIG="${INSTALLOHMYZSHCONFIG:-"true"}" +UPGRADE_PACKAGES="${UPGRADEPACKAGES:-"true"}" +USERNAME="${USERNAME:-"automatic"}" +USER_UID="${USERUID:-"automatic"}" +USER_GID="${USERGID:-"automatic"}" +ADD_NON_FREE_PACKAGES="${NONFREEPACKAGES:-"false"}" + +MARKER_FILE="/usr/local/etc/vscode-dev-containers/common" + +FEATURE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +# Debian / Ubuntu packages +install_debian_packages() { + # Ensure apt is in non-interactive to avoid prompts + export DEBIAN_FRONTEND=noninteractive + + local package_list="" + if [ "${PACKAGES_ALREADY_INSTALLED}" != "true" ]; then + package_list="${package_list} \ + apt-utils \ + openssh-client \ + gnupg2 \ + dirmngr \ + iproute2 \ + procps \ + lsof \ + htop \ + net-tools \ + psmisc \ + curl \ + tree \ + wget \ + rsync \ + ca-certificates \ + unzip \ + bzip2 \ + zip \ + nano \ + vim-tiny \ + less \ + jq \ + lsb-release \ + apt-transport-https \ + dialog \ + libc6 \ + libgcc1 \ + libkrb5-3 \ + libgssapi-krb5-2 \ + libicu[0-9][0-9] \ + liblttng-ust[0-9] \ + libstdc++6 \ + zlib1g \ + locales \ + sudo \ + ncdu \ + man-db \ + strace \ + manpages \ + manpages-dev \ + init-system-helpers" + + # Include libssl1.1 if available + if [[ ! -z $(apt-cache --names-only search ^libssl1.1$) ]]; then + package_list="${package_list} libssl1.1" + fi + + # Include libssl3 if available + if [[ ! -z $(apt-cache --names-only search ^libssl3$) ]]; then + package_list="${package_list} libssl3" + fi + + # Include appropriate version of libssl1.0.x if available + local libssl_package=$(dpkg-query -f '${db:Status-Abbrev}\t${binary:Package}\n' -W 'libssl1\.0\.?' 2>&1 || echo '') + if [ "$(echo "$libssl_package" | grep -o 'libssl1\.0\.[0-9]:' | uniq | sort | wc -l)" -eq 0 ]; then + if [[ ! -z $(apt-cache --names-only search ^libssl1.0.2$) ]]; then + # Debian 9 + package_list="${package_list} libssl1.0.2" + elif [[ ! -z $(apt-cache --names-only search ^libssl1.0.0$) ]]; then + # Ubuntu 18.04 + package_list="${package_list} libssl1.0.0" + fi + fi + + # Include git if not already installed (may be more recent than distro version) + if ! type git > /dev/null 2>&1; then + package_list="${package_list} git" + fi + fi + + # Needed for adding manpages-posix and manpages-posix-dev which are non-free packages in Debian + if [ "${ADD_NON_FREE_PACKAGES}" = "true" ]; then + # Bring in variables from /etc/os-release like VERSION_CODENAME + sed -i -E "s/deb http:\/\/(deb|httpredir)\.debian\.org\/debian ${VERSION_CODENAME} main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME} main contrib non-free/" /etc/apt/sources.list + sed -i -E "s/deb-src http:\/\/(deb|httredir)\.debian\.org\/debian ${VERSION_CODENAME} main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME} main contrib non-free/" /etc/apt/sources.list + sed -i -E "s/deb http:\/\/(deb|httpredir)\.debian\.org\/debian ${VERSION_CODENAME}-updates main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME}-updates main contrib non-free/" /etc/apt/sources.list + sed -i -E "s/deb-src http:\/\/(deb|httpredir)\.debian\.org\/debian ${VERSION_CODENAME}-updates main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME}-updates main contrib non-free/" /etc/apt/sources.list + sed -i "s/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main contrib non-free/" /etc/apt/sources.list + sed -i "s/deb-src http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main contrib non-free/" /etc/apt/sources.list + sed -i "s/deb http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main/deb http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main contrib non-free/" /etc/apt/sources.list + sed -i "s/deb-src http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main/deb http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main contrib non-free/" /etc/apt/sources.list + # Handle bullseye location for security https://www.debian.org/releases/bullseye/amd64/release-notes/ch-information.en.html + sed -i "s/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main contrib non-free/" /etc/apt/sources.list + sed -i "s/deb-src http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main contrib non-free/" /etc/apt/sources.list + echo "Running apt-get update..." + package_list="${package_list} manpages-posix manpages-posix-dev" + fi + + # Install the list of packages + echo "Packages to verify are installed: ${package_list}" + rm -rf /var/lib/apt/lists/* + apt-get update -y + apt-get -y install --no-install-recommends ${package_list} 2> >( grep -v 'debconf: delaying package configuration, since apt-utils is not installed' >&2 ) + + # Install zsh (and recommended packages) if needed + if [ "${INSTALL_ZSH}" = "true" ] && ! type zsh > /dev/null 2>&1; then + apt-get install -y zsh + fi + + # Get to latest versions of all packages + if [ "${UPGRADE_PACKAGES}" = "true" ]; then + apt-get -y upgrade --no-install-recommends + apt-get autoremove -y + fi + + # Ensure at least the en_US.UTF-8 UTF-8 locale is available = common need for both applications and things like the agnoster ZSH theme. + if [ "${LOCALE_ALREADY_SET}" != "true" ] && ! grep -o -E '^\s*en_US.UTF-8\s+UTF-8' /etc/locale.gen > /dev/null; then + echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen + locale-gen + LOCALE_ALREADY_SET="true" + fi + + PACKAGES_ALREADY_INSTALLED="true" + + # Clean up + apt-get -y clean + rm -rf /var/lib/apt/lists/* +} + +# RedHat / RockyLinux / CentOS / Fedora packages +install_redhat_packages() { + local package_list="" + local remove_epel="false" + local install_cmd=dnf + if ! type dnf > /dev/null 2>&1; then + install_cmd=yum + fi + + if [ "${PACKAGES_ALREADY_INSTALLED}" != "true" ]; then + package_list="${package_list} \ + gawk \ + openssh-clients \ + gnupg2 \ + iproute \ + procps \ + lsof \ + net-tools \ + psmisc \ + wget \ + ca-certificates \ + rsync \ + unzip \ + zip \ + nano \ + vim-minimal \ + less \ + jq \ + openssl-libs \ + krb5-libs \ + libicu \ + zlib \ + sudo \ + sed \ + grep \ + which \ + man-db \ + strace" + + # rockylinux:9 installs 'curl-minimal' which clashes with 'curl' + # Install 'curl' for every OS except this rockylinux:9 + if [[ "${ID}" = "rocky" ]] && [[ "${VERSION}" != *"9."* ]]; then + package_list="${package_list} curl" + fi + + # Install OpenSSL 1.0 compat if needed + if ${install_cmd} -q list compat-openssl10 >/dev/null 2>&1; then + package_list="${package_list} compat-openssl10" + fi + + # Install lsb_release if available + if ${install_cmd} -q list redhat-lsb-core >/dev/null 2>&1; then + package_list="${package_list} redhat-lsb-core" + fi + + # Install git if not already installed (may be more recent than distro version) + if ! type git > /dev/null 2>&1; then + package_list="${package_list} git" + fi + + # Install EPEL repository if needed (required to install 'jq' for CentOS) + if ! ${install_cmd} -q list jq >/dev/null 2>&1; then + ${install_cmd} -y install epel-release + remove_epel="true" + fi + fi + + # Install zsh if needed + if [ "${INSTALL_ZSH}" = "true" ] && ! type zsh > /dev/null 2>&1; then + package_list="${package_list} zsh" + fi + + ${install_cmd} -y install ${package_list} + + # Get to latest versions of all packages + if [ "${UPGRADE_PACKAGES}" = "true" ]; then + ${install_cmd} upgrade -y + fi + + if [[ "${remove_epel}" = "true" ]]; then + ${install_cmd} -y remove epel-release + fi + + PACKAGES_ALREADY_INSTALLED="true" +} + +# Alpine Linux packages +install_alpine_packages() { + apk update + + if [ "${PACKAGES_ALREADY_INSTALLED}" != "true" ]; then + apk add --no-cache \ + openssh-client \ + gnupg \ + procps \ + lsof \ + htop \ + net-tools \ + psmisc \ + curl \ + wget \ + rsync \ + ca-certificates \ + unzip \ + zip \ + nano \ + vim \ + less \ + jq \ + libgcc \ + libstdc++ \ + krb5-libs \ + libintl \ + libssl1.1 \ + lttng-ust \ + tzdata \ + userspace-rcu \ + zlib \ + sudo \ + coreutils \ + sed \ + grep \ + which \ + ncdu \ + shadow \ + strace + + # Install man pages - package name varies between 3.12 and earlier versions + if apk info man > /dev/null 2>&1; then + apk add --no-cache man man-pages + else + apk add --no-cache mandoc man-pages + fi + + # Install git if not already installed (may be more recent than distro version) + if ! type git > /dev/null 2>&1; then + apk add --no-cache git + fi + fi + + # Install zsh if needed + if [ "${INSTALL_ZSH}" = "true" ] && ! type zsh > /dev/null 2>&1; then + apk add --no-cache zsh + fi + + PACKAGES_ALREADY_INSTALLED="true" +} + +# ****************** +# ** Main section ** +# ****************** + +if [ "$(id -u)" -ne 0 ]; then + echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.' + exit 1 +fi + +# Load markers to see which steps have already run +if [ -f "${MARKER_FILE}" ]; then + echo "Marker file found:" + cat "${MARKER_FILE}" + source "${MARKER_FILE}" +fi + +# Ensure that login shells get the correct path if the user updated the PATH using ENV. +rm -f /etc/profile.d/00-restore-env.sh +echo "export PATH=${PATH//$(sh -lc 'echo $PATH')/\$PATH}" > /etc/profile.d/00-restore-env.sh +chmod +x /etc/profile.d/00-restore-env.sh + +# Bring in ID, ID_LIKE, VERSION_ID, VERSION_CODENAME +. /etc/os-release +# Get an adjusted ID independent of distro variants +if [ "${ID}" = "debian" ] || [ "${ID_LIKE}" = "debian" ]; then + ADJUSTED_ID="debian" +elif [[ "${ID}" = "rhel" || "${ID}" = "fedora" || "${ID}" = "mariner" || "${ID_LIKE}" = *"rhel"* || "${ID_LIKE}" = *"fedora"* || "${ID_LIKE}" = *"mariner"* ]]; then + ADJUSTED_ID="rhel" +elif [ "${ID}" = "alpine" ]; then + ADJUSTED_ID="alpine" +else + echo "Linux distro ${ID} not supported." + exit 1 +fi + +# Install packages for appropriate OS +case "${ADJUSTED_ID}" in + "debian") + install_debian_packages + ;; + "rhel") + install_redhat_packages + ;; + "alpine") + install_alpine_packages + ;; +esac + +# If in automatic mode, determine if a user already exists, if not use vscode +if [ "${USERNAME}" = "auto" ] || [ "${USERNAME}" = "automatic" ]; then + if [ "${_REMOTE_USER}" != "root" ]; then + USERNAME="${_REMOTE_USER}" + else + USERNAME="" + POSSIBLE_USERS=("devcontainer" "vscode" "node" "codespace" "$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd)") + for CURRENT_USER in "${POSSIBLE_USERS[@]}"; do + if id -u ${CURRENT_USER} > /dev/null 2>&1; then + USERNAME=${CURRENT_USER} + break + fi + done + if [ "${USERNAME}" = "" ]; then + USERNAME=vscode + fi + fi +elif [ "${USERNAME}" = "none" ]; then + USERNAME=root + USER_UID=0 + USER_GID=0 +fi +# Create or update a non-root user to match UID/GID. +group_name="${USERNAME}" +if id -u ${USERNAME} > /dev/null 2>&1; then + # User exists, update if needed + if [ "${USER_GID}" != "automatic" ] && [ "$USER_GID" != "$(id -g $USERNAME)" ]; then + group_name="$(id -gn $USERNAME)" + groupmod --gid $USER_GID ${group_name} + usermod --gid $USER_GID $USERNAME + fi + if [ "${USER_UID}" != "automatic" ] && [ "$USER_UID" != "$(id -u $USERNAME)" ]; then + usermod --uid $USER_UID $USERNAME + fi +else + # Create user + if [ "${USER_GID}" = "automatic" ]; then + groupadd $USERNAME + else + groupadd --gid $USER_GID $USERNAME + fi + if [ "${USER_UID}" = "automatic" ]; then + useradd -s /bin/bash --gid $USERNAME -m $USERNAME + else + useradd -s /bin/bash --uid $USER_UID --gid $USERNAME -m $USERNAME + fi +fi + +# Add add sudo support for non-root user +if [ "${USERNAME}" != "root" ] && [ "${EXISTING_NON_ROOT_USER}" != "${USERNAME}" ]; then + echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME + chmod 0440 /etc/sudoers.d/$USERNAME + EXISTING_NON_ROOT_USER="${USERNAME}" +fi + +# ********************************* +# ** Shell customization section ** +# ********************************* + +if [ "${USERNAME}" = "root" ]; then + user_home="/root" +# Check if user already has a home directory other than /home/${USERNAME} +elif [ "/home/${USERNAME}" != $( getent passwd $USERNAME | cut -d: -f6 ) ]; then + user_home=$( getent passwd $USERNAME | cut -d: -f6 ) +else + user_home="/home/${USERNAME}" + if [ ! -d "${user_home}" ]; then + mkdir -p "${user_home}" + chown ${USERNAME}:${group_name} "${user_home}" + fi +fi + +# Restore user .bashrc / .profile / .zshrc defaults from skeleton file if it doesn't exist or is empty +possible_rc_files=( ".bashrc" ".profile" ) +[ "$INSTALL_OH_MY_ZSH_CONFIG" == "true" ] && possible_rc_files+=('.zshrc') +[ "$INSTALL_ZSH" == "true" ] && possible_rc_files+=('.zprofile') +for rc_file in "${possible_rc_files[@]}"; do + if [ -f "/etc/skel/${rc_file}" ]; then + if [ ! -e "${user_home}/${rc_file}" ] || [ ! -s "${user_home}/${rc_file}" ]; then + cp "/etc/skel/${rc_file}" "${user_home}/${rc_file}" + chown ${USERNAME}:${group_name} "${user_home}/${rc_file}" + fi + fi +done + +# Add RC snippet and custom bash prompt +if [ "${RC_SNIPPET_ALREADY_ADDED}" != "true" ]; then + case "${ADJUSTED_ID}" in + "debian") + global_rc_path="/etc/bash.bashrc" + ;; + "rhel") + global_rc_path="/etc/bashrc" + ;; + "alpine") + global_rc_path="/etc/bash/bashrc" + # /etc/bash/bashrc does not exist in alpine 3.14 & 3.15 + mkdir -p /etc/bash + ;; + esac + cat "${FEATURE_DIR}/scripts/rc_snippet.sh" >> ${global_rc_path} + cat "${FEATURE_DIR}/scripts/bash_theme_snippet.sh" >> "${user_home}/.bashrc" + if [ "${USERNAME}" != "root" ]; then + cat "${FEATURE_DIR}/scripts/bash_theme_snippet.sh" >> "/root/.bashrc" + chown ${USERNAME}:${group_name} "${user_home}/.bashrc" + fi + RC_SNIPPET_ALREADY_ADDED="true" +fi + +# Optionally configure zsh and Oh My Zsh! +if [ "${INSTALL_ZSH}" = "true" ]; then + if [ ! -f "${user_home}/.zprofile" ] || ! grep -Fxq 'source $HOME/.profile' "${user_home}/.zprofile" ; then + echo 'source $HOME/.profile' >> "${user_home}/.zprofile" + fi + + if [ "${ZSH_ALREADY_INSTALLED}" != "true" ]; then + if [ "${ADJUSTED_ID}" = "rhel" ]; then + global_rc_path="/etc/zshrc" + else + global_rc_path="/etc/zsh/zshrc" + fi + cat "${FEATURE_DIR}/scripts/rc_snippet.sh" >> ${global_rc_path} + ZSH_ALREADY_INSTALLED="true" + fi + + if [ "${CONFIGURE_ZSH_AS_DEFAULT_SHELL}" == "true" ]; then + # Fixing chsh always asking for a password on alpine linux + # ref: https://askubuntu.com/questions/812420/chsh-always-asking-a-password-and-get-pam-authentication-failure. + if [ ! -f "/etc/pam.d/chsh" ] || ! grep -Eq '^auth(.*)pam_rootok\.so$' /etc/pam.d/chsh; then + echo "auth sufficient pam_rootok.so" >> /etc/pam.d/chsh + elif [[ -n "$(awk '/^auth(.*)pam_rootok\.so$/ && !/^auth[[:blank:]]+sufficient[[:blank:]]+pam_rootok\.so$/' /etc/pam.d/chsh)" ]]; then + awk '/^auth(.*)pam_rootok\.so$/ { $2 = "sufficient" } { print }' /etc/pam.d/chsh > /tmp/chsh.tmp && mv /tmp/chsh.tmp /etc/pam.d/chsh + fi + + chsh --shell /bin/zsh ${USERNAME} + fi + + # Adapted, simplified inline Oh My Zsh! install steps that adds, defaults to a codespaces theme. + # See https://github.com/ohmyzsh/ohmyzsh/blob/master/tools/install.sh for official script. + if [ "${INSTALL_OH_MY_ZSH}" = "true" ]; then + user_rc_file="${user_home}/.zshrc" + oh_my_install_dir="${user_home}/.oh-my-zsh" + template_path="${oh_my_install_dir}/templates/zshrc.zsh-template" + if [ ! -d "${oh_my_install_dir}" ]; then + umask g-w,o-w + mkdir -p ${oh_my_install_dir} + git clone --depth=1 \ + -c core.eol=lf \ + -c core.autocrlf=false \ + -c fsck.zeroPaddedFilemode=ignore \ + -c fetch.fsck.zeroPaddedFilemode=ignore \ + -c receive.fsck.zeroPaddedFilemode=ignore \ + "https://github.com/ohmyzsh/ohmyzsh" "${oh_my_install_dir}" 2>&1 + + # Shrink git while still enabling updates + cd "${oh_my_install_dir}" + git repack -a -d -f --depth=1 --window=1 + fi + + # Add Dev Containers theme + mkdir -p ${oh_my_install_dir}/custom/themes + cp -f "${FEATURE_DIR}/scripts/devcontainers.zsh-theme" "${oh_my_install_dir}/custom/themes/devcontainers.zsh-theme" + ln -sf "${oh_my_install_dir}/custom/themes/devcontainers.zsh-theme" "${oh_my_install_dir}/custom/themes/codespaces.zsh-theme" + + # Add devcontainer .zshrc template + if [ "$INSTALL_OH_MY_ZSH_CONFIG" = "true" ]; then + echo -e "$(cat "${template_path}")\nDISABLE_AUTO_UPDATE=true\nDISABLE_UPDATE_PROMPT=true" > ${user_rc_file} + sed -i -e 's/ZSH_THEME=.*/ZSH_THEME="devcontainers"/g' ${user_rc_file} + fi + + # Copy to non-root user if one is specified + if [ "${USERNAME}" != "root" ]; then + copy_to_user_files=("${oh_my_install_dir}") + [ -f "$user_rc_file" ] && copy_to_user_files+=("$user_rc_file") + cp -rf "${copy_to_user_files[@]}" /root + chown -R ${USERNAME}:${group_name} "${copy_to_user_files[@]}" + fi + fi +fi + +# ********************************* +# ** Ensure config directory ** +# ********************************* +user_config_dir="${user_home}/.config" +if [ ! -d "${user_config_dir}" ]; then + mkdir -p "${user_config_dir}" + chown ${USERNAME}:${group_name} "${user_config_dir}" +fi + +# **************************** +# ** Utilities and commands ** +# **************************** + +# code shim, it fallbacks to code-insiders if code is not available +cp -f "${FEATURE_DIR}/bin/code" /usr/local/bin/ +chmod +rx /usr/local/bin/code + +# systemctl shim for Debian/Ubuntu - tells people to use 'service' if systemd is not running +if [ "${ADJUSTED_ID}" = "debian" ]; then + cp -f "${FEATURE_DIR}/bin/systemctl" /usr/local/bin/systemctl + chmod +rx /usr/local/bin/systemctl +fi + +# Persist image metadata info, script if meta.env found in same directory +if [ -f "/usr/local/etc/vscode-dev-containers/meta.env" ] || [ -f "/usr/local/etc/dev-containers/meta.env" ]; then + cp -f "${FEATURE_DIR}/bin/devcontainer-info" /usr/local/bin/devcontainer-info + chmod +rx /usr/local/bin/devcontainer-info +fi + +# Write marker file +if [ ! -d "/usr/local/etc/vscode-dev-containers" ]; then + mkdir -p "$(dirname "${MARKER_FILE}")" +fi +echo -e "\ + PACKAGES_ALREADY_INSTALLED=${PACKAGES_ALREADY_INSTALLED}\n\ + LOCALE_ALREADY_SET=${LOCALE_ALREADY_SET}\n\ + EXISTING_NON_ROOT_USER=${EXISTING_NON_ROOT_USER}\n\ + RC_SNIPPET_ALREADY_ADDED=${RC_SNIPPET_ALREADY_ADDED}\n\ + ZSH_ALREADY_INSTALLED=${ZSH_ALREADY_INSTALLED}" > "${MARKER_FILE}" + +echo "Done!" diff --git a/.devcontainer/.devpod-internal/0/scripts/bash_theme_snippet.sh b/.devcontainer/.devpod-internal/0/scripts/bash_theme_snippet.sh new file mode 100644 index 0000000..a028e4b --- /dev/null +++ b/.devcontainer/.devpod-internal/0/scripts/bash_theme_snippet.sh @@ -0,0 +1,25 @@ + +# bash theme - partly inspired by https://github.com/ohmyzsh/ohmyzsh/blob/master/themes/robbyrussell.zsh-theme +__bash_prompt() { + local userpart='`export XIT=$? \ + && [ ! -z "${GITHUB_USER}" ] && echo -n "\[\033[0;32m\]@${GITHUB_USER} " || echo -n "\[\033[0;32m\]\u " \ + && [ "$XIT" -ne "0" ] && echo -n "\[\033[1;31m\]➜" || echo -n "\[\033[0m\]➜"`' + local gitbranch='`\ + if [ "$(git config --get devcontainers-theme.hide-status 2>/dev/null)" != 1 ] && [ "$(git config --get codespaces-theme.hide-status 2>/dev/null)" != 1 ]; then \ + export BRANCH=$(git --no-optional-locks symbolic-ref --short HEAD 2>/dev/null || git --no-optional-locks rev-parse --short HEAD 2>/dev/null); \ + if [ "${BRANCH}" != "" ]; then \ + echo -n "\[\033[0;36m\](\[\033[1;31m\]${BRANCH}" \ + && if [ "$(git config --get devcontainers-theme.show-dirty 2>/dev/null)" = 1 ] && \ + git --no-optional-locks ls-files --error-unmatch -m --directory --no-empty-directory -o --exclude-standard ":/*" > /dev/null 2>&1; then \ + echo -n " \[\033[1;33m\]✗"; \ + fi \ + && echo -n "\[\033[0;36m\]) "; \ + fi; \ + fi`' + local lightblue='\[\033[1;34m\]' + local removecolor='\[\033[0m\]' + PS1="${userpart} ${lightblue}\w ${gitbranch}${removecolor}\$ " + unset -f __bash_prompt +} +__bash_prompt +export PROMPT_DIRTRIM=4 diff --git a/.devcontainer/.devpod-internal/0/scripts/devcontainers.zsh-theme b/.devcontainer/.devpod-internal/0/scripts/devcontainers.zsh-theme new file mode 100644 index 0000000..ff11c91 --- /dev/null +++ b/.devcontainer/.devpod-internal/0/scripts/devcontainers.zsh-theme @@ -0,0 +1,26 @@ +# Oh My Zsh! theme - partly inspired by https://github.com/ohmyzsh/ohmyzsh/blob/master/themes/robbyrussell.zsh-theme +__zsh_prompt() { + local prompt_username + if [ ! -z "${GITHUB_USER}" ]; then + prompt_username="@${GITHUB_USER}" + else + prompt_username="%n" + fi + PROMPT="%{$fg[green]%}${prompt_username} %(?:%{$reset_color%}➜ :%{$fg_bold[red]%}➜ )" # User/exit code arrow + PROMPT+='%{$fg_bold[blue]%}%(5~|%-1~/…/%3~|%4~)%{$reset_color%} ' # cwd + PROMPT+='`\ + if [ "$(git config --get devcontainers-theme.hide-status 2>/dev/null)" != 1 ] && [ "$(git config --get codespaces-theme.hide-status 2>/dev/null)" != 1 ]; then \ + export BRANCH=$(git --no-optional-locks symbolic-ref --short HEAD 2>/dev/null || git --no-optional-locks rev-parse --short HEAD 2>/dev/null); \ + if [ "${BRANCH}" != "" ]; then \ + echo -n "%{$fg_bold[cyan]%}(%{$fg_bold[red]%}${BRANCH}" \ + && if [ "$(git config --get devcontainers-theme.show-dirty 2>/dev/null)" = 1 ] && \ + git --no-optional-locks ls-files --error-unmatch -m --directory --no-empty-directory -o --exclude-standard ":/*" > /dev/null 2>&1; then \ + echo -n " %{$fg_bold[yellow]%}✗"; \ + fi \ + && echo -n "%{$fg_bold[cyan]%})%{$reset_color%} "; \ + fi; \ + fi`' + PROMPT+='%{$fg[white]%}$ %{$reset_color%}' + unset -f __zsh_prompt +} +__zsh_prompt diff --git a/.devcontainer/.devpod-internal/0/scripts/rc_snippet.sh b/.devcontainer/.devpod-internal/0/scripts/rc_snippet.sh new file mode 100644 index 0000000..4810cd9 --- /dev/null +++ b/.devcontainer/.devpod-internal/0/scripts/rc_snippet.sh @@ -0,0 +1,26 @@ + +if [ -z "${USER}" ]; then export USER=$(whoami); fi +if [[ "${PATH}" != *"$HOME/.local/bin"* ]]; then export PATH="${PATH}:$HOME/.local/bin"; fi + +# Display optional first run image specific notice if configured and terminal is interactive +if [ -t 1 ] && [[ "${TERM_PROGRAM}" = "vscode" || "${TERM_PROGRAM}" = "codespaces" ]] && [ ! -f "$HOME/.config/vscode-dev-containers/first-run-notice-already-displayed" ]; then + if [ -f "/usr/local/etc/vscode-dev-containers/first-run-notice.txt" ]; then + cat "/usr/local/etc/vscode-dev-containers/first-run-notice.txt" + elif [ -f "/workspaces/.codespaces/shared/first-run-notice.txt" ]; then + cat "/workspaces/.codespaces/shared/first-run-notice.txt" + fi + mkdir -p "$HOME/.config/vscode-dev-containers" + # Mark first run notice as displayed after 10s to avoid problems with fast terminal refreshes hiding it + ((sleep 10s; touch "$HOME/.config/vscode-dev-containers/first-run-notice-already-displayed") &) +fi + +# Set the default git editor if not already set +if [ -z "$(git config --get core.editor)" ] && [ -z "${GIT_EDITOR}" ]; then + if [ "${TERM_PROGRAM}" = "vscode" ]; then + if [[ -n $(command -v code-insiders) && -z $(command -v code) ]]; then + export GIT_EDITOR="code-insiders --wait" + else + export GIT_EDITOR="code --wait" + fi + fi +fi diff --git a/.devcontainer/.devpod-internal/1/NOTES.md b/.devcontainer/.devpod-internal/1/NOTES.md new file mode 100644 index 0000000..b8156f8 --- /dev/null +++ b/.devcontainer/.devpod-internal/1/NOTES.md @@ -0,0 +1,16 @@ +## Limitations + +This docker-in-docker Dev Container Feature is roughly based on the [official docker-in-docker wrapper script](https://github.com/moby/moby/blob/master/hack/dind) that is part of the [Moby project](https://mobyproject.org/). With this in mind: +* As the name implies, the Feature is expected to work when the host is running Docker (or the OSS Moby container engine it is built on). It may be possible to get running in other container engines, but it has not been tested with them. +* The host and the container must be running on the same chip architecture. You will not be able to use it with an emulated x86 image with Docker Desktop on an Apple Silicon Mac, like in this example: + ``` + FROM --platform=linux/amd64 mcr.microsoft.com/devcontainers/typescript-node:16 + ``` + See [Issue #219](https://github.com/devcontainers/features/issues/219) for more details. + + +## OS Support + +This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed. + +`bash` is required to execute the `install.sh` script. diff --git a/.devcontainer/.devpod-internal/1/README.md b/.devcontainer/.devpod-internal/1/README.md new file mode 100644 index 0000000..bfca773 --- /dev/null +++ b/.devcontainer/.devpod-internal/1/README.md @@ -0,0 +1,51 @@ + +# Docker (Docker-in-Docker) (docker-in-docker) + +Create child containers *inside* a container, independent from the host's docker instance. Installs Docker extension in the container along with needed CLIs. + +## Example Usage + +```json +"features": { + "ghcr.io/devcontainers/features/docker-in-docker:2": {} +} +``` + +## Options + +| Options Id | Description | Type | Default Value | +|-----|-----|-----|-----| +| version | Select or enter a Docker/Moby Engine version. (Availability can vary by OS version.) | string | latest | +| moby | Install OSS Moby build instead of Docker CE | boolean | true | +| dockerDashComposeVersion | Default version of Docker Compose (v1 or v2 or none) | string | v1 | +| azureDnsAutoDetection | Allow automatically setting the dockerd DNS server when the installation script detects it is running in Azure | boolean | true | +| dockerDefaultAddressPool | Define default address pools for Docker networks. e.g. base=192.168.0.0/16,size=24 | string | - | +| installDockerBuildx | Install Docker Buildx | boolean | true | + +## Customizations + +### VS Code Extensions + +- `ms-azuretools.vscode-docker` + +## Limitations + +This docker-in-docker Dev Container Feature is roughly based on the [official docker-in-docker wrapper script](https://github.com/moby/moby/blob/master/hack/dind) that is part of the [Moby project](https://mobyproject.org/). With this in mind: +* As the name implies, the Feature is expected to work when the host is running Docker (or the OSS Moby container engine it is built on). It may be possible to get running in other container engines, but it has not been tested with them. +* The host and the container must be running on the same chip architecture. You will not be able to use it with an emulated x86 image with Docker Desktop on an Apple Silicon Mac, like in this example: + ``` + FROM --platform=linux/amd64 mcr.microsoft.com/devcontainers/typescript-node:16 + ``` + See [Issue #219](https://github.com/devcontainers/features/issues/219) for more details. + + +## OS Support + +This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed. + +`bash` is required to execute the `install.sh` script. + + +--- + +_Note: This file was auto-generated from the [devcontainer-feature.json](https://github.com/devcontainers/features/blob/main/src/docker-in-docker/devcontainer-feature.json). Add additional notes to a `NOTES.md`._ diff --git a/.devcontainer/.devpod-internal/1/devcontainer-feature.json b/.devcontainer/.devpod-internal/1/devcontainer-feature.json new file mode 100644 index 0000000..366905c --- /dev/null +++ b/.devcontainer/.devpod-internal/1/devcontainer-feature.json @@ -0,0 +1,72 @@ +{ + "id": "docker-in-docker", + "version": "2.7.1", + "name": "Docker (Docker-in-Docker)", + "documentationURL": "https://github.com/devcontainers/features/tree/main/src/docker-in-docker", + "description": "Create child containers *inside* a container, independent from the host's docker instance. Installs Docker extension in the container along with needed CLIs.", + "options": { + "version": { + "type": "string", + "proposals": [ + "latest", + "none", + "20.10" + ], + "default": "latest", + "description": "Select or enter a Docker/Moby Engine version. (Availability can vary by OS version.)" + }, + "moby": { + "type": "boolean", + "default": true, + "description": "Install OSS Moby build instead of Docker CE" + }, + "dockerDashComposeVersion": { + "type": "string", + "enum": [ + "none", + "v1", + "v2" + ], + "default": "v1", + "description": "Default version of Docker Compose (v1 or v2 or none)" + }, + "azureDnsAutoDetection": { + "type": "boolean", + "default": true, + "description": "Allow automatically setting the dockerd DNS server when the installation script detects it is running in Azure" + }, + "dockerDefaultAddressPool": { + "type": "string", + "default": "", + "proposals": [], + "description": "Define default address pools for Docker networks. e.g. base=192.168.0.0/16,size=24" + }, + "installDockerBuildx": { + "type": "boolean", + "default": true, + "description": "Install Docker Buildx" + } + }, + "entrypoint": "/usr/local/share/docker-init.sh", + "privileged": true, + "containerEnv": { + "DOCKER_BUILDKIT": "1" + }, + "customizations": { + "vscode": { + "extensions": [ + "ms-azuretools.vscode-docker" + ] + } + }, + "mounts": [ + { + "source": "dind-var-lib-docker-${devcontainerId}", + "target": "/var/lib/docker", + "type": "volume" + } + ], + "installsAfter": [ + "ghcr.io/devcontainers/features/common-utils" + ] +} diff --git a/.devcontainer/.devpod-internal/1/devcontainer-features-install.sh b/.devcontainer/.devpod-internal/1/devcontainer-features-install.sh new file mode 100644 index 0000000..46a334d --- /dev/null +++ b/.devcontainer/.devpod-internal/1/devcontainer-features-install.sh @@ -0,0 +1,35 @@ +#!/bin/sh +set -e + +on_exit () { + [ $? -eq 0 ] && exit + echo 'ERROR: Feature "Docker (Docker-in-Docker)" (ghcr.io/devcontainers/features/docker-in-docker) failed to install! Look at the documentation at ${documentation} for help troubleshooting this error.' +} + +trap on_exit EXIT + +set -a +. ../devcontainer-features.builtin.env +. ./devcontainer-features.env +set +a + +echo =========================================================================== + +echo 'Feature : Docker (Docker-in-Docker)' +echo 'Description : Create child containers *inside* a container, independent from the host'\''s docker instance. Installs Docker extension in the container along with needed CLIs.' +echo 'Id : ghcr.io/devcontainers/features/docker-in-docker' +echo 'Version : 2.7.1' +echo 'Documentation : https://github.com/devcontainers/features/tree/main/src/docker-in-docker' +echo 'Options :' +echo ' DOCKERDEFAULTADDRESSPOOL="" + INSTALLDOCKERBUILDX="true" + VERSION="latest" + MOBY="true" + DOCKERDASHCOMPOSEVERSION="v1" + AZUREDNSAUTODETECTION="true"' +echo 'Environment :' +printenv +echo =========================================================================== + +chmod +x ./install.sh +./install.sh diff --git a/.devcontainer/.devpod-internal/1/devcontainer-features.env b/.devcontainer/.devpod-internal/1/devcontainer-features.env new file mode 100644 index 0000000..35cfbf2 --- /dev/null +++ b/.devcontainer/.devpod-internal/1/devcontainer-features.env @@ -0,0 +1,6 @@ +DOCKERDEFAULTADDRESSPOOL="" +INSTALLDOCKERBUILDX="true" +VERSION="latest" +MOBY="true" +DOCKERDASHCOMPOSEVERSION="v1" +AZUREDNSAUTODETECTION="true" \ No newline at end of file diff --git a/.devcontainer/.devpod-internal/1/install.sh b/.devcontainer/.devpod-internal/1/install.sh new file mode 100755 index 0000000..3d47d46 --- /dev/null +++ b/.devcontainer/.devpod-internal/1/install.sh @@ -0,0 +1,482 @@ +#!/usr/bin/env bash +#------------------------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. +#------------------------------------------------------------------------------------------------------------- +# +# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/docker-in-docker.md +# Maintainer: The Dev Container spec maintainers + + +DOCKER_VERSION="${VERSION:-"latest"}" # The Docker/Moby Engine + CLI should match in version +USE_MOBY="${MOBY:-"true"}" +DOCKER_DASH_COMPOSE_VERSION="${DOCKERDASHCOMPOSEVERSION:-"v1"}" # v1 or v2 or none +AZURE_DNS_AUTO_DETECTION="${AZUREDNSAUTODETECTION:-"true"}" +DOCKER_DEFAULT_ADDRESS_POOL="${DOCKERDEFAULTADDRESSPOOL}" +USERNAME="${USERNAME:-"${_REMOTE_USER:-"automatic"}"}" +INSTALL_DOCKER_BUILDX="${INSTALLDOCKERBUILDX:-"true"}" +MICROSOFT_GPG_KEYS_URI="https://packages.microsoft.com/keys/microsoft.asc" +DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES="bookworm buster bullseye bionic focal jammy" +DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES="bookworm buster bullseye bionic focal hirsute impish jammy" + +# Default: Exit on any failure. +set -e + +# Clean up +rm -rf /var/lib/apt/lists/* + +# Setup STDERR. +err() { + echo "(!) $*" >&2 +} + +if [ "$(id -u)" -ne 0 ]; then + err 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.' + exit 1 +fi + +################### +# Helper Functions +# See: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/shared/utils.sh +################### + +# Determine the appropriate non-root user +if [ "${USERNAME}" = "auto" ] || [ "${USERNAME}" = "automatic" ]; then + USERNAME="" + POSSIBLE_USERS=("vscode" "node" "codespace" "$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd)") + for CURRENT_USER in "${POSSIBLE_USERS[@]}"; do + if id -u ${CURRENT_USER} > /dev/null 2>&1; then + USERNAME=${CURRENT_USER} + break + fi + done + if [ "${USERNAME}" = "" ]; then + USERNAME=root + fi +elif [ "${USERNAME}" = "none" ] || ! id -u ${USERNAME} > /dev/null 2>&1; then + USERNAME=root +fi + +apt_get_update() +{ + if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then + echo "Running apt-get update..." + apt-get update -y + fi +} + +# Checks if packages are installed and installs them if not +check_packages() { + if ! dpkg -s "$@" > /dev/null 2>&1; then + apt_get_update + apt-get -y install --no-install-recommends "$@" + fi +} + +# Figure out correct version of a three part version number is not passed +find_version_from_git_tags() { + local variable_name=$1 + local requested_version=${!variable_name} + if [ "${requested_version}" = "none" ]; then return; fi + local repository=$2 + local prefix=${3:-"tags/v"} + local separator=${4:-"."} + local last_part_optional=${5:-"false"} + if [ "$(echo "${requested_version}" | grep -o "." | wc -l)" != "2" ]; then + local escaped_separator=${separator//./\\.} + local last_part + if [ "${last_part_optional}" = "true" ]; then + last_part="(${escaped_separator}[0-9]+)?" + else + last_part="${escaped_separator}[0-9]+" + fi + local regex="${prefix}\\K[0-9]+${escaped_separator}[0-9]+${last_part}$" + local version_list="$(git ls-remote --tags ${repository} | grep -oP "${regex}" | tr -d ' ' | tr "${separator}" "." | sort -rV)" + if [ "${requested_version}" = "latest" ] || [ "${requested_version}" = "current" ] || [ "${requested_version}" = "lts" ]; then + declare -g ${variable_name}="$(echo "${version_list}" | head -n 1)" + else + set +e + declare -g ${variable_name}="$(echo "${version_list}" | grep -E -m 1 "^${requested_version//./\\.}([\\.\\s]|$)")" + set -e + fi + fi + if [ -z "${!variable_name}" ] || ! echo "${version_list}" | grep "^${!variable_name//./\\.}$" > /dev/null 2>&1; then + err "Invalid ${variable_name} value: ${requested_version}\nValid values:\n${version_list}" >&2 + exit 1 + fi + echo "${variable_name}=${!variable_name}" +} + +########################################### +# Start docker-in-docker installation +########################################### + +# Ensure apt is in non-interactive to avoid prompts +export DEBIAN_FRONTEND=noninteractive + + +# Source /etc/os-release to get OS info +. /etc/os-release +# Fetch host/container arch. +architecture="$(dpkg --print-architecture)" + +# Check if distro is supported +if [ "${USE_MOBY}" = "true" ]; then + if [[ "${DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES}" != *"${VERSION_CODENAME}"* ]]; then + err "Unsupported distribution version '${VERSION_CODENAME}'. To resolve, either: (1) set feature option '\"moby\": false' , or (2) choose a compatible OS distribution" + err "Support distributions include: ${DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES}" + exit 1 + fi + echo "Distro codename '${VERSION_CODENAME}' matched filter '${DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES}'" +else + if [[ "${DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES}" != *"${VERSION_CODENAME}"* ]]; then + err "Unsupported distribution version '${VERSION_CODENAME}'. To resolve, please choose a compatible OS distribution" + err "Support distributions include: ${DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES}" + exit 1 + fi + echo "Distro codename '${VERSION_CODENAME}' matched filter '${DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES}'" +fi + +# Install dependencies +check_packages apt-transport-https curl ca-certificates pigz iptables gnupg2 dirmngr wget +if ! type git > /dev/null 2>&1; then + check_packages git +fi + +# Swap to legacy iptables for compatibility +if type iptables-legacy > /dev/null 2>&1; then + update-alternatives --set iptables /usr/sbin/iptables-legacy + update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy +fi + + + +# Set up the necessary apt repos (either Microsoft's or Docker's) +if [ "${USE_MOBY}" = "true" ]; then + + # Name of open source engine/cli + engine_package_name="moby-engine" + cli_package_name="moby-cli" + + # Import key safely and import Microsoft apt repo + curl -sSL ${MICROSOFT_GPG_KEYS_URI} | gpg --dearmor > /usr/share/keyrings/microsoft-archive-keyring.gpg + echo "deb [arch=${architecture} signed-by=/usr/share/keyrings/microsoft-archive-keyring.gpg] https://packages.microsoft.com/repos/microsoft-${ID}-${VERSION_CODENAME}-prod ${VERSION_CODENAME} main" > /etc/apt/sources.list.d/microsoft.list +else + # Name of licensed engine/cli + engine_package_name="docker-ce" + cli_package_name="docker-ce-cli" + + # Import key safely and import Docker apt repo + curl -fsSL https://download.docker.com/linux/${ID}/gpg | gpg --dearmor > /usr/share/keyrings/docker-archive-keyring.gpg + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/${ID} ${VERSION_CODENAME} stable" > /etc/apt/sources.list.d/docker.list +fi + +# Refresh apt lists +apt-get update + +# Soft version matching +if [ "${DOCKER_VERSION}" = "latest" ] || [ "${DOCKER_VERSION}" = "lts" ] || [ "${DOCKER_VERSION}" = "stable" ]; then + # Empty, meaning grab whatever "latest" is in apt repo + engine_version_suffix="" + cli_version_suffix="" +else + # Fetch a valid version from the apt-cache (eg: the Microsoft repo appends +azure, breakfix, etc...) + docker_version_dot_escaped="${DOCKER_VERSION//./\\.}" + docker_version_dot_plus_escaped="${docker_version_dot_escaped//+/\\+}" + # Regex needs to handle debian package version number format: https://www.systutorials.com/docs/linux/man/5-deb-version/ + docker_version_regex="^(.+:)?${docker_version_dot_plus_escaped}([\\.\\+ ~:-]|$)" + set +e # Don't exit if finding version fails - will handle gracefully + cli_version_suffix="=$(apt-cache madison ${cli_package_name} | awk -F"|" '{print $2}' | sed -e 's/^[ \t]*//' | grep -E -m 1 "${docker_version_regex}")" + engine_version_suffix="=$(apt-cache madison ${engine_package_name} | awk -F"|" '{print $2}' | sed -e 's/^[ \t]*//' | grep -E -m 1 "${docker_version_regex}")" + set -e + if [ -z "${engine_version_suffix}" ] || [ "${engine_version_suffix}" = "=" ] || [ -z "${cli_version_suffix}" ] || [ "${cli_version_suffix}" = "=" ] ; then + err "No full or partial Docker / Moby version match found for \"${DOCKER_VERSION}\" on OS ${ID} ${VERSION_CODENAME} (${architecture}). Available versions:" + apt-cache madison ${cli_package_name} | awk -F"|" '{print $2}' | grep -oP '^(.+:)?\K.+' + exit 1 + fi + echo "engine_version_suffix ${engine_version_suffix}" + echo "cli_version_suffix ${cli_version_suffix}" +fi + +# Install Docker / Moby CLI if not already installed +if type docker > /dev/null 2>&1 && type dockerd > /dev/null 2>&1; then + echo "Docker / Moby CLI and Engine already installed." +else + if [ "${USE_MOBY}" = "true" ]; then + # Install engine + set +e # Handle error gracefully + apt-get -y install --no-install-recommends moby-cli${cli_version_suffix} moby-buildx moby-engine${engine_version_suffix} + if [ $? -ne 0 ]; then + err "Packages for moby not available in OS ${ID} ${VERSION_CODENAME} (${architecture}). To resolve, either: (1) set feature option '\"moby\": false' , or (2) choose a compatible OS version (eg: 'ubuntu-20.04')." + exit 1 + fi + set -e + + # Install compose + apt-get -y install --no-install-recommends moby-compose || err "Package moby-compose (Docker Compose v2) not available for OS ${ID} ${VERSION_CODENAME} (${architecture}). Skipping." + else + apt-get -y install --no-install-recommends docker-ce-cli${cli_version_suffix} docker-ce${engine_version_suffix} + # Install compose + apt-get -y install --no-install-recommends docker-compose-plugin || echo "(*) Package docker-compose-plugin (Docker Compose v2) not available for OS ${ID} ${VERSION_CODENAME} (${architecture}). Skipping." + fi +fi + +echo "Finished installing docker / moby!" + +# If 'docker-compose' command is to be included +if [ "${DOCKER_DASH_COMPOSE_VERSION}" != "none" ]; then + # Install Docker Compose if not already installed and is on a supported architecture + if type docker-compose > /dev/null 2>&1; then + echo "Docker Compose v1 already installed." + else + target_compose_arch="${architecture}" + if [ "${target_compose_arch}" = "amd64" ]; then + target_compose_arch="x86_64" + fi + if [ "${target_compose_arch}" != "x86_64" ]; then + # Use pip to get a version that runs on this architecture + check_packages python3-minimal python3-pip libffi-dev python3-venv + export PIPX_HOME=/usr/local/pipx + mkdir -p ${PIPX_HOME} + export PIPX_BIN_DIR=/usr/local/bin + export PYTHONUSERBASE=/tmp/pip-tmp + export PIP_CACHE_DIR=/tmp/pip-tmp/cache + pipx_bin=pipx + if ! type pipx > /dev/null 2>&1; then + pip3 install --disable-pip-version-check --no-cache-dir --user pipx + pipx_bin=/tmp/pip-tmp/bin/pipx + fi + + set +e + ${pipx_bin} install --pip-args '--no-cache-dir --force-reinstall' docker-compose + exit_code=$? + set -e + + if [ ${exit_code} -ne 0 ]; then + # Temporary: https://github.com/devcontainers/features/issues/616 + # See https://github.com/yaml/pyyaml/issues/601 + echo "(*) Failed to install docker-compose via pipx. Trying via pip3..." + + export PYTHONUSERBASE=/usr/local + pip3 install --disable-pip-version-check --no-cache-dir --user "Cython<3.0" pyyaml wheel docker-compose --no-build-isolation + fi + + rm -rf /tmp/pip-tmp + else + compose_v1_version="1" + find_version_from_git_tags compose_v1_version "https://github.com/docker/compose" "tags/" + echo "(*) Installing docker-compose ${compose_v1_version}..." + curl -fsSL "https://github.com/docker/compose/releases/download/${compose_v1_version}/docker-compose-Linux-x86_64" -o /usr/local/bin/docker-compose + chmod +x /usr/local/bin/docker-compose + fi + fi + + # Install docker-compose switch if not already installed - https://github.com/docker/compose-switch#manual-installation + current_v1_compose_path="$(which docker-compose)" + target_v1_compose_path="$(dirname "${current_v1_compose_path}")/docker-compose-v1" + if ! type compose-switch > /dev/null 2>&1; then + echo "(*) Installing compose-switch..." + compose_switch_version="latest" + find_version_from_git_tags compose_switch_version "https://github.com/docker/compose-switch" + curl -fsSL "https://github.com/docker/compose-switch/releases/download/v${compose_switch_version}/docker-compose-linux-${architecture}" -o /usr/local/bin/compose-switch + chmod +x /usr/local/bin/compose-switch + # TODO: Verify checksum once available: https://github.com/docker/compose-switch/issues/11 + + # Setup v1 CLI as alternative in addition to compose-switch (which maps to v2) + mv "${current_v1_compose_path}" "${target_v1_compose_path}" + update-alternatives --install /usr/local/bin/docker-compose docker-compose /usr/local/bin/compose-switch 99 + update-alternatives --install /usr/local/bin/docker-compose docker-compose "${target_v1_compose_path}" 1 + fi + if [ "${DOCKER_DASH_COMPOSE_VERSION}" = "v1" ]; then + update-alternatives --set docker-compose "${target_v1_compose_path}" + else + update-alternatives --set docker-compose /usr/local/bin/compose-switch + fi +fi + +# If init file already exists, exit +if [ -f "/usr/local/share/docker-init.sh" ]; then + echo "/usr/local/share/docker-init.sh already exists, so exiting." + # Clean up + rm -rf /var/lib/apt/lists/* + exit 0 +fi +echo "docker-init doesn't exist, adding..." + +if ! cat /etc/group | grep -e "^docker:" > /dev/null 2>&1; then + groupadd -r docker +fi + +usermod -aG docker ${USERNAME} + +if [ "${INSTALL_DOCKER_BUILDX}" = "true" ]; then + buildx_version="latest" + find_version_from_git_tags buildx_version "https://github.com/docker/buildx" "refs/tags/v" + + echo "(*) Installing buildx ${buildx_version}..." + buildx_file_name="buildx-v${buildx_version}.linux-${architecture}" + cd /tmp && wget "https://github.com/docker/buildx/releases/download/v${buildx_version}/${buildx_file_name}" + + mkdir -p ${_REMOTE_USER_HOME}/.docker/cli-plugins + mv ${buildx_file_name} ${_REMOTE_USER_HOME}/.docker/cli-plugins/docker-buildx + chmod +x ${_REMOTE_USER_HOME}/.docker/cli-plugins/docker-buildx + + chown -R "${USERNAME}:docker" "${_REMOTE_USER_HOME}/.docker" + chmod -R g+r+w "${_REMOTE_USER_HOME}/.docker" + find "${_REMOTE_USER_HOME}/.docker" -type d -print0 | xargs -n 1 -0 chmod g+s +fi + +tee /usr/local/share/docker-init.sh > /dev/null \ +<< EOF +#!/bin/sh +#------------------------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. +#------------------------------------------------------------------------------------------------------------- + +set -e + +AZURE_DNS_AUTO_DETECTION=${AZURE_DNS_AUTO_DETECTION} +DOCKER_DEFAULT_ADDRESS_POOL=${DOCKER_DEFAULT_ADDRESS_POOL} +EOF + +tee -a /usr/local/share/docker-init.sh > /dev/null \ +<< 'EOF' +dockerd_start="AZURE_DNS_AUTO_DETECTION=${AZURE_DNS_AUTO_DETECTION} DOCKER_DEFAULT_ADDRESS_POOL=${DOCKER_DEFAULT_ADDRESS_POOL} $(cat << 'INNEREOF' + # explicitly remove dockerd and containerd PID file to ensure that it can start properly if it was stopped uncleanly + find /run /var/run -iname 'docker*.pid' -delete || : + find /run /var/run -iname 'container*.pid' -delete || : + + # -- Start: dind wrapper script -- + # Maintained: https://github.com/moby/moby/blob/master/hack/dind + + export container=docker + + if [ -d /sys/kernel/security ] && ! mountpoint -q /sys/kernel/security; then + mount -t securityfs none /sys/kernel/security || { + echo >&2 'Could not mount /sys/kernel/security.' + echo >&2 'AppArmor detection and --privileged mode might break.' + } + fi + + # Mount /tmp (conditionally) + if ! mountpoint -q /tmp; then + mount -t tmpfs none /tmp + fi + + set_cgroup_nesting() + { + # cgroup v2: enable nesting + if [ -f /sys/fs/cgroup/cgroup.controllers ]; then + # move the processes from the root group to the /init group, + # otherwise writing subtree_control fails with EBUSY. + # An error during moving non-existent process (i.e., "cat") is ignored. + mkdir -p /sys/fs/cgroup/init + xargs -rn1 < /sys/fs/cgroup/cgroup.procs > /sys/fs/cgroup/init/cgroup.procs || : + # enable controllers + sed -e 's/ / +/g' -e 's/^/+/' < /sys/fs/cgroup/cgroup.controllers \ + > /sys/fs/cgroup/cgroup.subtree_control + fi + } + + # Set cgroup nesting, retrying if necessary + retry_cgroup_nesting=0 + + until [ "${retry_cgroup_nesting}" -eq "5" ]; + do + set +e + set_cgroup_nesting + + if [ $? -ne 0 ]; then + echo "(*) cgroup v2: Failed to enable nesting, retrying..." + else + break + fi + + retry_cgroup_nesting=`expr $retry_cgroup_nesting + 1` + set -e + done + + # -- End: dind wrapper script -- + + # Handle DNS + set +e + cat /etc/resolv.conf | grep -i 'internal.cloudapp.net' > /dev/null 2>&1 + if [ $? -eq 0 ] && [ "${AZURE_DNS_AUTO_DETECTION}" = "true" ] + then + echo "Setting dockerd Azure DNS." + CUSTOMDNS="--dns 168.63.129.16" + else + echo "Not setting dockerd DNS manually." + CUSTOMDNS="" + fi + set -e + + if [ -z "$DOCKER_DEFAULT_ADDRESS_POOL" ] + then + DEFAULT_ADDRESS_POOL="" + else + DEFAULT_ADDRESS_POOL="--default-address-pool $DOCKER_DEFAULT_ADDRESS_POOL" + fi + + # Start docker/moby engine + ( dockerd $CUSTOMDNS $DEFAULT_ADDRESS_POOL > /tmp/dockerd.log 2>&1 ) & +INNEREOF +)" + +sudo_if() { + COMMAND="$*" + + if [ "$(id -u)" -ne 0 ]; then + sudo $COMMAND + else + $COMMAND + fi +} + +retry_docker_start_count=0 +docker_ok="false" + +until [ "${docker_ok}" = "true" ] || [ "${retry_docker_start_count}" -eq "5" ]; +do + # Start using sudo if not invoked as root + if [ "$(id -u)" -ne 0 ]; then + sudo /bin/sh -c "${dockerd_start}" + else + eval "${dockerd_start}" + fi + + retry_count=0 + until [ "${docker_ok}" = "true" ] || [ "${retry_count}" -eq "5" ]; + do + sleep 1s + set +e + docker info > /dev/null 2>&1 && docker_ok="true" + set -e + + retry_count=`expr $retry_count + 1` + done + + if [ "${docker_ok}" != "true" ] && [ "${retry_docker_start_count}" != "4" ]; then + echo "(*) Failed to start docker, retrying..." + set +e + sudo_if pkill dockerd + sudo_if pkill containerd + set -e + fi + + retry_docker_start_count=`expr $retry_docker_start_count + 1` +done + +# Execute whatever commands were passed in (if any). This allows us +# to set this script to ENTRYPOINT while still executing the default CMD. +exec "$@" +EOF + +chmod +x /usr/local/share/docker-init.sh +chown ${USERNAME}:root /usr/local/share/docker-init.sh + +# Clean up +rm -rf /var/lib/apt/lists/* + +echo 'docker-in-docker-debian script has completed!' diff --git a/.devcontainer/.devpod-internal/2/NOTES.md b/.devcontainer/.devpod-internal/2/NOTES.md new file mode 100644 index 0000000..6626d2c --- /dev/null +++ b/.devcontainer/.devpod-internal/2/NOTES.md @@ -0,0 +1,19 @@ +## Ingress and port forwarding + +When configuring [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) for your Kubernetes cluster, note that by default Kubernetes will bind to a specific interface's IP rather than localhost or all interfaces. This is why you need to use the Kubernetes Node's IP when connecting - even if there's only one Node as in the case of Minikube. Port forwarding in Remote - Containers will allow you to specify `:` in either the `forwardPorts` property or through the port forwarding UI in VS Code. + +However, GitHub Codespaces does not yet support this capability, so you'll need to use `kubectl` to forward the port to localhost. This adds minimal overhead since everything is on the same machine. E.g.: + +```bash +minikube start +minikube addons enable ingress +# Run this to forward to localhost in the background +nohup kubectl port-forward --pod-running-timeout=24h -n ingress-nginx service/ingress-nginx-controller :80 & +``` + + +## OS Support + +This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed. + +`bash` is required to execute the `install.sh` script. diff --git a/.devcontainer/.devpod-internal/2/README.md b/.devcontainer/.devpod-internal/2/README.md new file mode 100644 index 0000000..81ce8c5 --- /dev/null +++ b/.devcontainer/.devpod-internal/2/README.md @@ -0,0 +1,45 @@ + +# Kubectl, Helm, and Minikube (kubectl-helm-minikube) + +Installs latest version of kubectl, Helm, and optionally minikube. Auto-detects latest versions and installs needed dependencies. + +## Example Usage + +```json +"features": { + "ghcr.io/devcontainers/features/kubectl-helm-minikube:1": {} +} +``` + +## Options + +| Options Id | Description | Type | Default Value | +|-----|-----|-----|-----| +| version | Select or enter a Kubernetes version to install | string | latest | +| helm | Select or enter a Helm version to install | string | latest | +| minikube | Select or enter a Minikube version to install | string | latest | + +## Ingress and port forwarding + +When configuring [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) for your Kubernetes cluster, note that by default Kubernetes will bind to a specific interface's IP rather than localhost or all interfaces. This is why you need to use the Kubernetes Node's IP when connecting - even if there's only one Node as in the case of Minikube. Port forwarding in Remote - Containers will allow you to specify `:` in either the `forwardPorts` property or through the port forwarding UI in VS Code. + +However, GitHub Codespaces does not yet support this capability, so you'll need to use `kubectl` to forward the port to localhost. This adds minimal overhead since everything is on the same machine. E.g.: + +```bash +minikube start +minikube addons enable ingress +# Run this to forward to localhost in the background +nohup kubectl port-forward --pod-running-timeout=24h -n ingress-nginx service/ingress-nginx-controller :80 & +``` + + +## OS Support + +This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed. + +`bash` is required to execute the `install.sh` script. + + +--- + +_Note: This file was auto-generated from the [devcontainer-feature.json](https://github.com/devcontainers/features/blob/main/src/kubectl-helm-minikube/devcontainer-feature.json). Add additional notes to a `NOTES.md`._ diff --git a/.devcontainer/.devpod-internal/2/devcontainer-feature.json b/.devcontainer/.devpod-internal/2/devcontainer-feature.json new file mode 100644 index 0000000..4206772 --- /dev/null +++ b/.devcontainer/.devpod-internal/2/devcontainer-feature.json @@ -0,0 +1,50 @@ +{ + "id": "kubectl-helm-minikube", + "version": "1.1.5", + "name": "Kubectl, Helm, and Minikube", + "documentationURL": "https://github.com/devcontainers/features/tree/main/src/kubectl-helm-minikube", + "description": "Installs latest version of kubectl, Helm, and optionally minikube. Auto-detects latest versions and installs needed dependencies.", + "options": { + "version": { + "type": "string", + "proposals": [ + "latest", + "none", + "1.23", + "1.22", + "1.21", + "none" + ], + "default": "latest", + "description": "Select or enter a Kubernetes version to install" + }, + "helm": { + "type": "string", + "proposals": [ + "latest", + "none" + ], + "default": "latest", + "description": "Select or enter a Helm version to install" + }, + "minikube": { + "type": "string", + "proposals": [ + "latest", + "none" + ], + "default": "latest", + "description": "Select or enter a Minikube version to install" + } + }, + "mounts": [ + { + "source": "minikube-config", + "target": "/home/vscode/.minikube", + "type": "volume" + } + ], + "installsAfter": [ + "ghcr.io/devcontainers/features/common-utils" + ] +} diff --git a/.devcontainer/.devpod-internal/2/devcontainer-features-install.sh b/.devcontainer/.devpod-internal/2/devcontainer-features-install.sh new file mode 100644 index 0000000..8c6c942 --- /dev/null +++ b/.devcontainer/.devpod-internal/2/devcontainer-features-install.sh @@ -0,0 +1,32 @@ +#!/bin/sh +set -e + +on_exit () { + [ $? -eq 0 ] && exit + echo 'ERROR: Feature "Kubectl, Helm, and Minikube" (ghcr.io/devcontainers/features/kubectl-helm-minikube) failed to install! Look at the documentation at ${documentation} for help troubleshooting this error.' +} + +trap on_exit EXIT + +set -a +. ../devcontainer-features.builtin.env +. ./devcontainer-features.env +set +a + +echo =========================================================================== + +echo 'Feature : Kubectl, Helm, and Minikube' +echo 'Description : Installs latest version of kubectl, Helm, and optionally minikube. Auto-detects latest versions and installs needed dependencies.' +echo 'Id : ghcr.io/devcontainers/features/kubectl-helm-minikube' +echo 'Version : 1.1.5' +echo 'Documentation : https://github.com/devcontainers/features/tree/main/src/kubectl-helm-minikube' +echo 'Options :' +echo ' HELM="latest" + MINIKUBE="latest" + VERSION="latest"' +echo 'Environment :' +printenv +echo =========================================================================== + +chmod +x ./install.sh +./install.sh diff --git a/.devcontainer/.devpod-internal/2/devcontainer-features.env b/.devcontainer/.devpod-internal/2/devcontainer-features.env new file mode 100644 index 0000000..2dd023e --- /dev/null +++ b/.devcontainer/.devpod-internal/2/devcontainer-features.env @@ -0,0 +1,3 @@ +HELM="latest" +MINIKUBE="latest" +VERSION="latest" \ No newline at end of file diff --git a/.devcontainer/.devpod-internal/2/install.sh b/.devcontainer/.devpod-internal/2/install.sh new file mode 100755 index 0000000..35444c5 --- /dev/null +++ b/.devcontainer/.devpod-internal/2/install.sh @@ -0,0 +1,239 @@ +#!/usr/bin/env bash +#------------------------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. +#------------------------------------------------------------------------------------------------------------- +# +# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/kubectl-helm.md +# Maintainer: The VS Code and Codespaces Teams + +set -e + +# Clean up +rm -rf /var/lib/apt/lists/* + +KUBECTL_VERSION="${VERSION:-"latest"}" +HELM_VERSION="${HELM:-"latest"}" +MINIKUBE_VERSION="${MINIKUBE:-"latest"}" # latest is also valid + +KUBECTL_SHA256="${KUBECTL_SHA256:-"automatic"}" +HELM_SHA256="${HELM_SHA256:-"automatic"}" +MINIKUBE_SHA256="${MINIKUBE_SHA256:-"automatic"}" +USERNAME="${USERNAME:-"${_REMOTE_USER:-"automatic"}"}" + +HELM_GPG_KEYS_URI="https://raw.githubusercontent.com/helm/helm/main/KEYS" +GPG_KEY_SERVERS="keyserver hkp://keyserver.ubuntu.com +keyserver hkp://keyserver.ubuntu.com:80 +keyserver hkps://keys.openpgp.org +keyserver hkp://keyserver.pgp.com" + +if [ "$(id -u)" -ne 0 ]; then + echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.' + exit 1 +fi + +# Determine the appropriate non-root user +if [ "${USERNAME}" = "auto" ] || [ "${USERNAME}" = "automatic" ]; then + USERNAME="" + POSSIBLE_USERS=("vscode" "node" "codespace" "$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd)") + for CURRENT_USER in "${POSSIBLE_USERS[@]}"; do + if id -u ${CURRENT_USER} > /dev/null 2>&1; then + USERNAME=${CURRENT_USER} + break + fi + done + if [ "${USERNAME}" = "" ]; then + USERNAME=root + fi +elif [ "${USERNAME}" = "none" ] || ! id -u ${USERNAME} > /dev/null 2>&1; then + USERNAME=root +fi + +USERHOME="/home/$USERNAME" +if [ "$USERNAME" = "root" ]; then + USERHOME="/root" +fi + +# Figure out correct version of a three part version number is not passed +find_version_from_git_tags() { + local variable_name=$1 + local requested_version=${!variable_name} + if [ "${requested_version}" = "none" ]; then return; fi + local repository=$2 + local prefix=${3:-"tags/v"} + local separator=${4:-"."} + local last_part_optional=${5:-"false"} + if [ "$(echo "${requested_version}" | grep -o "." | wc -l)" != "2" ]; then + local escaped_separator=${separator//./\\.} + local last_part + if [ "${last_part_optional}" = "true" ]; then + last_part="(${escaped_separator}[0-9]+)?" + else + last_part="${escaped_separator}[0-9]+" + fi + local regex="${prefix}\\K[0-9]+${escaped_separator}[0-9]+${last_part}$" + local version_list="$(git ls-remote --tags ${repository} | grep -oP "${regex}" | tr -d ' ' | tr "${separator}" "." | sort -rV)" + if [ "${requested_version}" = "latest" ] || [ "${requested_version}" = "current" ] || [ "${requested_version}" = "lts" ]; then + declare -g ${variable_name}="$(echo "${version_list}" | head -n 1)" + else + set +e + declare -g ${variable_name}="$(echo "${version_list}" | grep -E -m 1 "^${requested_version//./\\.}([\\.\\s]|$)")" + set -e + fi + fi + if [ -z "${!variable_name}" ] || ! echo "${version_list}" | grep "^${!variable_name//./\\.}$" > /dev/null 2>&1; then + echo -e "Invalid ${variable_name} value: ${requested_version}\nValid values:\n${version_list}" >&2 + exit 1 + fi + echo "${variable_name}=${!variable_name}" +} + +apt_get_update() +{ + if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then + echo "Running apt-get update..." + apt-get update -y + fi +} + +# Checks if packages are installed and installs them if not +check_packages() { + if ! dpkg -s "$@" > /dev/null 2>&1; then + apt_get_update + apt-get -y install --no-install-recommends "$@" + fi +} + +# Ensure apt is in non-interactive to avoid prompts +export DEBIAN_FRONTEND=noninteractive + +# Install dependencies +check_packages curl ca-certificates coreutils gnupg2 dirmngr bash-completion +if ! type git > /dev/null 2>&1; then + check_packages git +fi + +architecture="$(uname -m)" +case $architecture in + x86_64) architecture="amd64";; + aarch64 | armv8*) architecture="arm64";; + aarch32 | armv7* | armvhf*) architecture="arm";; + i?86) architecture="386";; + *) echo "(!) Architecture $architecture unsupported"; exit 1 ;; +esac + +if [ ${KUBECTL_VERSION} != "none" ]; then + # Install the kubectl, verify checksum + echo "Downloading kubectl..." + if [ "${KUBECTL_VERSION}" = "latest" ] || [ "${KUBECTL_VERSION}" = "lts" ] || [ "${KUBECTL_VERSION}" = "current" ] || [ "${KUBECTL_VERSION}" = "stable" ]; then + KUBECTL_VERSION="$(curl -sSL https://dl.k8s.io/release/stable.txt)" + else + find_version_from_git_tags KUBECTL_VERSION https://github.com/kubernetes/kubernetes + fi + if [ "${KUBECTL_VERSION::1}" != 'v' ]; then + KUBECTL_VERSION="v${KUBECTL_VERSION}" + fi + curl -sSL -o /usr/local/bin/kubectl "https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/${architecture}/kubectl" + chmod 0755 /usr/local/bin/kubectl + if [ "$KUBECTL_SHA256" = "automatic" ]; then + KUBECTL_SHA256="$(curl -sSL "https://dl.k8s.io/${KUBECTL_VERSION}/bin/linux/${architecture}/kubectl.sha256")" + fi + ([ "${KUBECTL_SHA256}" = "dev-mode" ] || (echo "${KUBECTL_SHA256} */usr/local/bin/kubectl" | sha256sum -c -)) + if ! type kubectl > /dev/null 2>&1; then + echo '(!) kubectl installation failed!' + exit 1 + fi + + # kubectl bash completion + kubectl completion bash > /etc/bash_completion.d/kubectl + + # kubectl zsh completion + if [ -e "${USERHOME}}/.oh-my-zsh" ]; then + mkdir -p "${USERHOME}/.oh-my-zsh/completions" + kubectl completion zsh > "${USERHOME}/.oh-my-zsh/completions/_kubectl" + chown -R "${USERNAME}" "${USERHOME}/.oh-my-zsh" + fi +fi + +if [ ${HELM_VERSION} != "none" ]; then + # Install Helm, verify signature and checksum + echo "Downloading Helm..." + find_version_from_git_tags HELM_VERSION "https://github.com/helm/helm" + if [ "${HELM_VERSION::1}" != 'v' ]; then + HELM_VERSION="v${HELM_VERSION}" + fi + mkdir -p /tmp/helm + helm_filename="helm-${HELM_VERSION}-linux-${architecture}.tar.gz" + tmp_helm_filename="/tmp/helm/${helm_filename}" + curl -sSL "https://get.helm.sh/${helm_filename}" -o "${tmp_helm_filename}" + curl -sSL "https://github.com/helm/helm/releases/download/${HELM_VERSION}/${helm_filename}.asc" -o "${tmp_helm_filename}.asc" + export GNUPGHOME="/tmp/helm/gnupg" + mkdir -p "${GNUPGHOME}" + chmod 700 ${GNUPGHOME} + curl -sSL "${HELM_GPG_KEYS_URI}" -o /tmp/helm/KEYS + echo -e "disable-ipv6\n${GPG_KEY_SERVERS}" > ${GNUPGHOME}/dirmngr.conf + gpg -q --import "/tmp/helm/KEYS" + if ! gpg --verify "${tmp_helm_filename}.asc" > ${GNUPGHOME}/verify.log 2>&1; then + echo "Verification failed!" + cat /tmp/helm/gnupg/verify.log + exit 1 + fi + + if [ "${HELM_SHA256}" = "automatic" ]; then + curl -sSL "https://get.helm.sh/${helm_filename}.sha256" -o "${tmp_helm_filename}.sha256" + curl -sSL "https://github.com/helm/helm/releases/download/${HELM_VERSION}/${helm_filename}.sha256.asc" -o "${tmp_helm_filename}.sha256.asc" + if ! gpg --verify "${tmp_helm_filename}.sha256.asc" > /tmp/helm/gnupg/verify.log 2>&1; then + echo "Verification failed!" + cat /tmp/helm/gnupg/verify.log + exit 1 + fi + HELM_SHA256="$(cat "${tmp_helm_filename}.sha256")" + fi + + ([ "${HELM_SHA256}" = "dev-mode" ] || (echo "${HELM_SHA256} *${tmp_helm_filename}" | sha256sum -c -)) + tar xf "${tmp_helm_filename}" -C /tmp/helm + mv -f "/tmp/helm/linux-${architecture}/helm" /usr/local/bin/ + chmod 0755 /usr/local/bin/helm + rm -rf /tmp/helm + if ! type helm > /dev/null 2>&1; then + echo '(!) Helm installation failed!' + exit 1 + fi +fi + +# Install Minikube, verify checksum +if [ "${MINIKUBE_VERSION}" != "none" ]; then + echo "Downloading minikube..." + if [ "${MINIKUBE_VERSION}" = "latest" ] || [ "${MINIKUBE_VERSION}" = "lts" ] || [ "${MINIKUBE_VERSION}" = "current" ] || [ "${MINIKUBE_VERSION}" = "stable" ]; then + MINIKUBE_VERSION="latest" + else + find_version_from_git_tags MINIKUBE_VERSION https://github.com/kubernetes/minikube + if [ "${MINIKUBE_VERSION::1}" != "v" ]; then + MINIKUBE_VERSION="v${MINIKUBE_VERSION}" + fi + fi + # latest is also valid in the download URLs + curl -sSL -o /usr/local/bin/minikube "https://storage.googleapis.com/minikube/releases/${MINIKUBE_VERSION}/minikube-linux-${architecture}" + chmod 0755 /usr/local/bin/minikube + if [ "$MINIKUBE_SHA256" = "automatic" ]; then + MINIKUBE_SHA256="$(curl -sSL "https://storage.googleapis.com/minikube/releases/${MINIKUBE_VERSION}/minikube-linux-${architecture}.sha256")" + fi + ([ "${MINIKUBE_SHA256}" = "dev-mode" ] || (echo "${MINIKUBE_SHA256} */usr/local/bin/minikube" | sha256sum -c -)) + if ! type minikube > /dev/null 2>&1; then + echo '(!) minikube installation failed!' + exit 1 + fi + # Create minkube folder with correct privs in case a volume is mounted here + mkdir -p "${USERHOME}/.minikube" + chown -R $USERNAME "${USERHOME}/.minikube" + chmod -R u+wrx "${USERHOME}/.minikube" +fi + +if ! type docker > /dev/null 2>&1; then + echo -e '\n(*) Warning: The docker command was not found.\n\nYou can use one of the following scripts to install it:\n\nhttps://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/docker-in-docker.md\n\nor\n\nhttps://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/docker.md' +fi + +# Clean up +rm -rf /var/lib/apt/lists/* + +echo -e "\nDone!" diff --git a/.devcontainer/.devpod-internal/3/NOTES.md b/.devcontainer/.devpod-internal/3/NOTES.md new file mode 100644 index 0000000..19fe92f --- /dev/null +++ b/.devcontainer/.devpod-internal/3/NOTES.md @@ -0,0 +1,7 @@ + + +## OS Support + +This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed. + +`bash` is required to execute the `install.sh` script. diff --git a/.devcontainer/.devpod-internal/3/README.md b/.devcontainer/.devpod-internal/3/README.md new file mode 100644 index 0000000..a9e54fa --- /dev/null +++ b/.devcontainer/.devpod-internal/3/README.md @@ -0,0 +1,32 @@ + +# Git (from source) (git) + +Install an up-to-date version of Git, built from source as needed. Useful for when you want the latest and greatest features. Auto-detects latest stable version and installs needed dependencies. + +## Example Usage + +```json +"features": { + "ghcr.io/devcontainers/features/git:1": {} +} +``` + +## Options + +| Options Id | Description | Type | Default Value | +|-----|-----|-----|-----| +| version | Select or enter a Git version. | string | os-provided | +| ppa | Install from PPA if available | boolean | true | + + + +## OS Support + +This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed. + +`bash` is required to execute the `install.sh` script. + + +--- + +_Note: This file was auto-generated from the [devcontainer-feature.json](https://github.com/devcontainers/features/blob/main/src/git/devcontainer-feature.json). Add additional notes to a `NOTES.md`._ diff --git a/.devcontainer/.devpod-internal/3/devcontainer-feature.json b/.devcontainer/.devpod-internal/3/devcontainer-feature.json new file mode 100644 index 0000000..8cbca6c --- /dev/null +++ b/.devcontainer/.devpod-internal/3/devcontainer-feature.json @@ -0,0 +1,26 @@ +{ + "id": "git", + "version": "1.1.6", + "name": "Git (from source)", + "documentationURL": "https://github.com/devcontainers/features/tree/main/src/git", + "description": "Install an up-to-date version of Git, built from source as needed. Useful for when you want the latest and greatest features. Auto-detects latest stable version and installs needed dependencies.", + "options": { + "version": { + "type": "string", + "proposals": [ + "latest", + "os-provided" + ], + "default": "os-provided", + "description": "Select or enter a Git version." + }, + "ppa": { + "type": "boolean", + "default": true, + "description": "Install from PPA if available" + } + }, + "installsAfter": [ + "ghcr.io/devcontainers/features/common-utils" + ] +} diff --git a/.devcontainer/.devpod-internal/3/devcontainer-features-install.sh b/.devcontainer/.devpod-internal/3/devcontainer-features-install.sh new file mode 100644 index 0000000..745b154 --- /dev/null +++ b/.devcontainer/.devpod-internal/3/devcontainer-features-install.sh @@ -0,0 +1,31 @@ +#!/bin/sh +set -e + +on_exit () { + [ $? -eq 0 ] && exit + echo 'ERROR: Feature "Git (from source)" (ghcr.io/devcontainers/features/git) failed to install! Look at the documentation at ${documentation} for help troubleshooting this error.' +} + +trap on_exit EXIT + +set -a +. ../devcontainer-features.builtin.env +. ./devcontainer-features.env +set +a + +echo =========================================================================== + +echo 'Feature : Git (from source)' +echo 'Description : Install an up-to-date version of Git, built from source as needed. Useful for when you want the latest and greatest features. Auto-detects latest stable version and installs needed dependencies.' +echo 'Id : ghcr.io/devcontainers/features/git' +echo 'Version : 1.1.6' +echo 'Documentation : https://github.com/devcontainers/features/tree/main/src/git' +echo 'Options :' +echo ' VERSION="os-provided" + PPA="true"' +echo 'Environment :' +printenv +echo =========================================================================== + +chmod +x ./install.sh +./install.sh diff --git a/.devcontainer/.devpod-internal/3/devcontainer-features.env b/.devcontainer/.devpod-internal/3/devcontainer-features.env new file mode 100644 index 0000000..b16a182 --- /dev/null +++ b/.devcontainer/.devpod-internal/3/devcontainer-features.env @@ -0,0 +1,2 @@ +VERSION="os-provided" +PPA="true" \ No newline at end of file diff --git a/.devcontainer/.devpod-internal/3/install.sh b/.devcontainer/.devpod-internal/3/install.sh new file mode 100755 index 0000000..67338b8 --- /dev/null +++ b/.devcontainer/.devpod-internal/3/install.sh @@ -0,0 +1,151 @@ +#!/usr/bin/env bash +#------------------------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. +#------------------------------------------------------------------------------------------------------------- +# +# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/git-from-src.md +# Maintainer: The VS Code and Codespaces Teams + +GIT_VERSION=${VERSION} # 'system' checks the base image first, else installs 'latest' +USE_PPA_IF_AVAILABLE=${PPA} + +GIT_CORE_PPA_ARCHIVE_GPG_KEY=E1DD270288B4E6030699E45FA1715D88E1DF1F24 +GPG_KEY_SERVERS="keyserver hkp://keyserver.ubuntu.com +keyserver hkp://keyserver.ubuntu.com:80 +keyserver hkps://keys.openpgp.org +keyserver hkp://keyserver.pgp.com" + +set -e + +# Clean up +rm -rf /var/lib/apt/lists/* + +if [ "$(id -u)" -ne 0 ]; then + echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.' + exit 1 +fi + +# Import the specified key in a variable name passed in as +receive_gpg_keys() { + local keys=${!1} + local keyring_args="" + if [ ! -z "$2" ]; then + mkdir -p "$(dirname \"$2\")" + keyring_args="--no-default-keyring --keyring $2" + fi + + # Use a temporary location for gpg keys to avoid polluting image + export GNUPGHOME="/tmp/tmp-gnupg" + mkdir -p ${GNUPGHOME} + chmod 700 ${GNUPGHOME} + echo -e "disable-ipv6\n${GPG_KEY_SERVERS}" > ${GNUPGHOME}/dirmngr.conf + # GPG key download sometimes fails for some reason and retrying fixes it. + local retry_count=0 + local gpg_ok="false" + set +e + until [ "${gpg_ok}" = "true" ] || [ "${retry_count}" -eq "5" ]; + do + echo "(*) Downloading GPG key..." + ( echo "${keys}" | xargs -n 1 gpg -q ${keyring_args} --recv-keys) 2>&1 && gpg_ok="true" + if [ "${gpg_ok}" != "true" ]; then + echo "(*) Failed getting key, retring in 10s..." + (( retry_count++ )) + sleep 10s + fi + done + set -e + if [ "${gpg_ok}" = "false" ]; then + echo "(!) Failed to get gpg key." + exit 1 + fi +} + +apt_get_update() +{ + if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then + echo "Running apt-get update..." + apt-get update -y + fi +} + +# Checks if packages are installed and installs them if not +check_packages() { + if ! dpkg -s "$@" > /dev/null 2>&1; then + apt_get_update + apt-get -y install --no-install-recommends "$@" + fi +} + +export DEBIAN_FRONTEND=noninteractive + +# Source /etc/os-release to get OS info +. /etc/os-release + +# If the os provided version is "good enough", just install that. +if [ ${GIT_VERSION} = "os-provided" ] || [ ${GIT_VERSION} = "system" ]; then + if type git > /dev/null 2>&1; then + echo "Detected existing system install: $(git version)" + # Clean up + rm -rf /var/lib/apt/lists/* + exit 0 + fi + + echo "Installing git from OS apt repository" + check_packages git + # Clean up + rm -rf /var/lib/apt/lists/* + exit 0 +fi + +# If ubuntu, PPAs allowed, and latest - install from there +if ([ "${GIT_VERSION}" = "latest" ] || [ "${GIT_VERSION}" = "lts" ] || [ "${GIT_VERSION}" = "current" ]) && [ "${ID}" = "ubuntu" ] && [ "${USE_PPA_IF_AVAILABLE}" = "true" ]; then + echo "Using PPA to install latest git..." + check_packages apt-transport-https curl ca-certificates gnupg2 dirmngr + receive_gpg_keys GIT_CORE_PPA_ARCHIVE_GPG_KEY /usr/share/keyrings/gitcoreppa-archive-keyring.gpg + echo -e "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/gitcoreppa-archive-keyring.gpg] http://ppa.launchpad.net/git-core/ppa/ubuntu ${VERSION_CODENAME} main\ndeb-src [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/gitcoreppa-archive-keyring.gpg] http://ppa.launchpad.net/git-core/ppa/ubuntu ${VERSION_CODENAME} main" > /etc/apt/sources.list.d/git-core-ppa.list + apt-get update + apt-get -y install --no-install-recommends git + rm -rf "/tmp/tmp-gnupg" + rm -rf /var/lib/apt/lists/* + exit 0 +fi + +# Install required packages to build if missing +check_packages build-essential curl ca-certificates tar gettext libssl-dev zlib1g-dev libcurl?-openssl-dev libexpat1-dev + +# Partial version matching +if [ "$(echo "${GIT_VERSION}" | grep -o '\.' | wc -l)" != "2" ]; then + requested_version="${GIT_VERSION}" + version_list="$(curl -sSL -H "Accept: application/vnd.github.v3+json" "https://api.github.com/repos/git/git/tags" | grep -oP '"name":\s*"v\K[0-9]+\.[0-9]+\.[0-9]+"' | tr -d '"' | sort -rV )" + if [ "${requested_version}" = "latest" ] || [ "${requested_version}" = "lts" ] || [ "${requested_version}" = "current" ]; then + GIT_VERSION="$(echo "${version_list}" | head -n 1)" + else + set +e + GIT_VERSION="$(echo "${version_list}" | grep -E -m 1 "^${requested_version//./\\.}([\\.\\s]|$)")" + set -e + fi + if [ -z "${GIT_VERSION}" ] || ! echo "${version_list}" | grep "^${GIT_VERSION//./\\.}$" > /dev/null 2>&1; then + echo "Invalid git version: ${requested_version}" >&2 + exit 1 + fi +fi + +check_packages libpcre2-dev + +if [ "${VERSION_CODENAME}" = "focal" ] || [ "${VERSION_CODENAME}" = "bullseye" ]; then + check_packages libpcre2-posix2 +elif [ "${VERSION_CODENAME}" = "bionic" ] || [ "${VERSION_CODENAME}" = "buster" ]; then + check_packages libpcre2-posix0 +else + check_packages libpcre2-posix3 +fi + +echo "Downloading source for ${GIT_VERSION}..." +curl -sL https://github.com/git/git/archive/v${GIT_VERSION}.tar.gz | tar -xzC /tmp 2>&1 +echo "Building..." +cd /tmp/git-${GIT_VERSION} +make -s USE_LIBPCRE=YesPlease prefix=/usr/local sysconfdir=/etc all && make -s USE_LIBPCRE=YesPlease prefix=/usr/local sysconfdir=/etc install 2>&1 +rm -rf /tmp/git-${GIT_VERSION} +rm -rf /var/lib/apt/lists/* +echo "Done!" diff --git a/.devcontainer/.devpod-internal/Dockerfile-with-features b/.devcontainer/.devpod-internal/Dockerfile-with-features new file mode 100644 index 0000000..ae00229 --- /dev/null +++ b/.devcontainer/.devpod-internal/Dockerfile-with-features @@ -0,0 +1,39 @@ +# syntax=docker.io/docker/dockerfile:1.4 +ARG _DEV_CONTAINERS_BASE_IMAGE=placeholder + + +FROM $_DEV_CONTAINERS_BASE_IMAGE AS dev_containers_target_stage + +USER root + +COPY ./.devpod-internal/ /tmp/build-features/ +RUN chmod -R 0755 /tmp/build-features && ls /tmp/build-features + +RUN \ +echo "_CONTAINER_USER_HOME=$(getent passwd root | cut -d: -f6)" >> /tmp/build-features/devcontainer-features.builtin.env && \ +echo "_REMOTE_USER_HOME=$(getent passwd root | cut -d: -f6)" >> /tmp/build-features/devcontainer-features.builtin.env + + +RUN cd /tmp/build-features/0 \ +&& chmod +x ./devcontainer-features-install.sh \ +&& ./devcontainer-features-install.sh + +ENV DOCKER_BUILDKIT=1 +RUN cd /tmp/build-features/1 \ +&& chmod +x ./devcontainer-features-install.sh \ +&& ./devcontainer-features-install.sh + + +RUN cd /tmp/build-features/2 \ +&& chmod +x ./devcontainer-features-install.sh \ +&& ./devcontainer-features-install.sh + + +RUN cd /tmp/build-features/3 \ +&& chmod +x ./devcontainer-features-install.sh \ +&& ./devcontainer-features-install.sh + + + +ARG _DEV_CONTAINERS_IMAGE_USER=root +USER $_DEV_CONTAINERS_IMAGE_USER \ No newline at end of file diff --git a/.devcontainer/.devpod-internal/devcontainer-features.builtin.env b/.devcontainer/.devpod-internal/devcontainer-features.builtin.env new file mode 100644 index 0000000..3b25383 --- /dev/null +++ b/.devcontainer/.devpod-internal/devcontainer-features.builtin.env @@ -0,0 +1,2 @@ +_CONTAINER_USER=root +_REMOTE_USER=root diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index d26ef67..462c75e 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -2,47 +2,29 @@ // README at: https://github.com/devcontainers/templates/tree/main/src/kubernetes-helm-minikube { "name": "Kubernetes - Minikube-in-Docker", - "image": "mcr.microsoft.com/devcontainers/base:bullseye", + "image": "debian:bookworm", "features": { - "ghcr.io/devcontainers/features/common-utils:1": { - "installZsh": "true", - "username": "vscode", - "uid": "1000", - "gid": "1000", - "upgradePackages": "false", - "installOhMyZsh": "true", - "nonFreePackages": "true" + "ghcr.io/devcontainers/features/common-utils:2": { + "configureZshAsDefaultShell": true, + "installOhMyZsh": false }, - "ghcr.io/devcontainers/features/docker-in-docker:2": { - "enableNonRootDocker": "true", - "username": "vscode", - "moby": "true" - }, - "ghcr.io/devcontainers/features/kubectl-helm-minikube:1": { - "version": "latest", - "helm": "latest", - "minikube": "latest" - } + "ghcr.io/devcontainers/features/git:1": {}, + "ghcr.io/devcontainers/features/docker-in-docker:2": {}, + "ghcr.io/devcontainers/features/kubectl-helm-minikube:1": {} }, - "overrideFeatureInstallOrder": [ "ghcr.io/devcontainers/features/common-utils", "ghcr.io/devcontainers/features/docker-in-docker", "ghcr.io/devcontainers/features/kubectl-helm-minikube" ], - // Use 'forwardPorts' to make a list of ports inside the container available locally. // "forwardPorts": [], - // Use 'postCreateCommand' to run commands after the container is created. // "postCreateCommand": "kubectl version", - // Use 'postStartCommand' to run commands after the container is created like starting minikube. // "postStartCommand": "nohup bash -c 'minikube start &' > minikube.log 2>&1", - // Configure tool-specific properties. // "customizations": {}, - "containerUser": "vscode" // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. // "remoteUser": "root"