diff --git a/README.md b/README.md index 6ec3c924e..a0be2e520 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ + # Geodesic [![Build Status](https://github.com/cloudposse/geodesic/workflows/docker/badge.svg)](https://github.com/cloudposse/geodesic/actions?query=workflow%3Adocker) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fcloudposse%2Fgeodesic.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fcloudposse%2Fgeodesic?ref=badge_shield) [![Latest Release](https://img.shields.io/github/release/cloudposse/geodesic.svg)](https://github.com/cloudposse/geodesic/releases/latest) [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) [![Slack Archive](https://img.shields.io/badge/slack-archive-blue.svg)](https://archive.sweetops.com/geodesic) @@ -41,7 +42,6 @@ It provides a fully customizable framework for defining and building cloud infra It's works natively with Mac OSX, Linux, and [Windows 10 (WSL)](https://docs.microsoft.com/en-us/windows/wsl/install-win10). - --- This project is part of our comprehensive ["SweetOps"](https://cpco.io/sweetops) approach towards DevOps. @@ -66,7 +66,6 @@ It's 100% Open Source and licensed under the [APACHE2](LICENSE). - ## Screenshots @@ -108,6 +107,10 @@ chip takes several years to establish; we hope we will not have to wait that lon Want to learn more? [Check out our getting started with Geodesic guide!](https://docs.cloudposse.com/tutorials/geodesic-getting-started/) + + + + ## Usage @@ -195,6 +198,7 @@ Like this project? Please give it a ★ on [our GitHub](https://github.com/cloud Are you using this project or any of our other projects? Consider [leaving a testimonial][testimonial]. =) + ## Related Projects Check out these related projects. @@ -203,8 +207,6 @@ Check out these related projects. - [Build Harness](https://github.com/cloudposse/dev) - Collection of Makefiles to facilitate building Golang projects, Dockerfiles, Helm charts, and more - [terraform-aws-components](https://github.com/cloudposse/terraform-aws-components) - Catalog of reusable Terraform components and blueprints for provisioning reference architectures - - ## Help **Got a question?** We got answers. @@ -276,7 +278,7 @@ In general, PRs are welcome. We follow the typical "fork-and-pull" Git workflow. ## Copyright -Copyright © 2017-2021 [Cloud Posse, LLC](https://cpco.io/copyright) +Copyright © 2017-2022 [Cloud Posse, LLC](https://cpco.io/copyright) diff --git a/os/alpine/Dockerfile.alpine b/os/alpine/Dockerfile.alpine index 622303b83..d28cc0305 100644 --- a/os/alpine/Dockerfile.alpine +++ b/os/alpine/Dockerfile.alpine @@ -1,8 +1,10 @@ -ARG ALPINE_VERSION=3.13.5 +ARG ALPINE_VERSION=3.13.7 # https://cloud.google.com/sdk/docs/release-notes -ARG GOOGLE_CLOUD_SDK_VERSION=352.0.0 +ARG GOOGLE_CLOUD_SDK_VERSION=369.0.0 # https://github.com/ahmetb/kubectx/releases ARG KUBECTX_COMPLETION_VERSION=0.9.4 +# https://github.com/jonmosco/kube-ps1/releases +ARG KUBE_PS1_VERSION=0.7.0 # # Python Dependencies @@ -146,7 +148,7 @@ ADD https://raw.githubusercontent.com/ahmetb/kubectx/v${KUBECTX_COMPLETION_VERSI # # Install fancy Kube PS1 Prompt # -ENV KUBE_PS1_VERSION 0.7.0 +ARG KUBE_PS1_VERSION ADD https://raw.githubusercontent.com/jonmosco/kube-ps1/v${KUBE_PS1_VERSION}/kube-ps1.sh /etc/profile.d/prompt:kube-ps1.sh diff --git a/os/debian/Dockerfile.debian b/os/debian/Dockerfile.debian index 6753659af..8a46f0e45 100644 --- a/os/debian/Dockerfile.debian +++ b/os/debian/Dockerfile.debian @@ -1,12 +1,14 @@ -ARG DEBIAN_VERSION=10.10-slim +ARG DEBIAN_VERSION=10.11-slim # https://cloud.google.com/sdk/docs/release-notes -ARG GOOGLE_CLOUD_SDK_VERSION=352.0.0-0 +ARG GOOGLE_CLOUD_SDK_VERSION=369.0.0-0 # https://github.com/ahmetb/kubectx/releases ARG KUBECTX_COMPLETION_VERSION=0.9.4 +# https://github.com/jonmosco/kube-ps1/releases +ARG KUBE_PS1_VERSION=0.7.0 FROM debian:$DEBIAN_VERSION as python # Find the current version of Python at https://www.python.org/downloads/source/ -ARG PYTHON_VERSION=3.8.11 +ARG PYTHON_VERSION=3.8.12 # Debian comes with minimal Locale support. See https://github.com/docker-library/docs/pull/703/files # Recommended: LC_ALL=C.UTF-8 @@ -173,7 +175,7 @@ ADD https://raw.githubusercontent.com/ahmetb/kubectx/v${KUBECTX_COMPLETION_VERSI # # Install fancy Kube PS1 Prompt # https://github.com/jonmosco/kube-ps1/releases -ENV KUBE_PS1_VERSION 0.7.0 +ARG KUBE_PS1_VERSION ADD https://raw.githubusercontent.com/jonmosco/kube-ps1/v${KUBE_PS1_VERSION}/kube-ps1.sh /etc/profile.d/prompt:kube-ps1.sh diff --git a/packages.txt b/packages.txt index 0e1939c58..d0d3aa7f2 100644 --- a/packages.txt +++ b/packages.txt @@ -31,9 +31,11 @@ helm3@cloudposse helmfile@cloudposse jq kops@cloudposse -# The latest version of kubectl is wrong for all of our customers, so do not install it. -# Instead, install a compatible version. For now, track the latest AWS EKS version. -kubectl-1.16@cloudposse +# The latest version of kubectl is wrong for most of our customers, so do not install it. +# Instead, install a compatible version. For now, track the latest AWS EKS version, +# which will support the previous and current EKS versions, and support the newly +# released next version until we later update this to follow. +kubectl-1.21@cloudposse kubectx@cloudposse kubens@cloudposse less diff --git a/rootfs/etc/init.d/atmos.sh b/rootfs/etc/init.d/atmos.sh deleted file mode 100755 index 51fb9d7e9..000000000 --- a/rootfs/etc/init.d/atmos.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -# check if atmos base path is unset and verify that the stacks and components dir is in current directory -if [ -z $ATMOS_BASE_PATH ] && [ -d "${GEODESIC_WORKDIR}/stacks" -a -d "${GEODESIC_WORKDIR}/components" ]; then - export ATMOS_BASE_PATH=${GEODESIC_WORKDIR} - echo "Set ATMOS_BASE_PATH = ${GEODESIC_WORKDIR}" -fi diff --git a/rootfs/etc/profile.d/_workdir.sh b/rootfs/etc/profile.d/_workdir.sh new file mode 100644 index 000000000..5b977cb09 --- /dev/null +++ b/rootfs/etc/profile.d/_workdir.sh @@ -0,0 +1,60 @@ +# Files in the profile.d directory are executed by the lexicographical order of their file names. +# This file sets the working directory inside Geodesic to match the host directory Geodesic +# was launched from, if possible. If the host directory is not accessible, it sets the working directory to `/`. +# +# This file is named _workdir.sh. The leading underscore is needed to ensure this file executes before +# other files that may depend on it. The "w" is needed to ensure it is loaded *after* _preferences.sh +# + +function _file_device() { + df --output=source "$1" | tail -1 +} + +# file_on_host is true when the argument is a file or directory that appears to be on the Host file system. +# Intended to support files on user-defined bind mounts in addition to `/localhost`. +# This function is run by the command line prompt setup, so it should be very fast. +# Therefore we cache some info in the environment. +if df -a | grep -q /localhost; then + export GEODESIC_LOCALHOST_DEVICE=$(_file_device /localhost) +else + export GEODESIC_LOCALHOST_MISSING=true +fi + +function file_on_host() { + [[ $GEODESIC_LOCALHOST_MISSING != "true" ]] && [[ $(_file_device "$1") == ${GEODESIC_LOCALHOST_DEVICE} ]] +} + +function _default_initial_wd() { + if [[ -d /stacks ]]; then + # Newer default using `atmos` and stacks + export GEODESIC_WORKDIR="/" + else + # Older default working directory + export GEODESIC_WORKDIR="/conf" + fi + red "# Defaulting initial working directory to \"${GEODESIC_WORKDIR}\"" +} + +# You can set GEODESIC_WORKDIR in your Geodesic preferences to have full control of your starting working directory +if [[ -d $GEODESIC_WORKDIR ]]; then + [[ $SHLVL == 1 ]] && green "# Initial working directory configured as ${GEODESIC_WORKDIR}" +else + if [[ -d $GEODESIC_HOST_CWD ]]; then + if [[ -n $LOCAL_HOME ]] && $(file_on_host "$GEODESIC_HOST_CWD"); then + export GEODESIC_WORKDIR=$(readlink -e "${GEODESIC_HOST_CWD}") + green "# Initial working directory set from host CWD to ${GEODESIC_WORKDIR}" + else + red "# Host CWD \"${GEODESIC_HOST_CWD}\" does not appear to be accessible from this container" + _default_initial_wd + fi + else + red "# No configured working directory is accessible:" + red "# GEODESIC_WORKDIR is \"$GEODESIC_WORKDIR\"" + red "# GEODESIC_HOST_CWD is \"$GEODESIC_HOST_CWD\"" + _default_initial_wd + fi +fi + +[[ $SHLVL == 1 ]] && cd "${GEODESIC_WORKDIR}" + +unset -f _default_initial_wd diff --git a/rootfs/etc/profile.d/atmos.sh b/rootfs/etc/profile.d/atmos.sh new file mode 100644 index 000000000..f33f9b588 --- /dev/null +++ b/rootfs/etc/profile.d/atmos.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +function _configure_atmos_base_path() { + # Leave $ATMOS_BASE_PATH alone if it is already set + if [[ -n $ATMOS_BASE_PATH ]]; then + if [[ $SHLVL == 1 ]]; then + green "# Using configured $ATMOS_BASE_PATH of \"$ATMOS_BASE_PATH\"" + fi + return + fi + + # If $GEODESIC_WORKDIR contains both a "stacks" and "components" directory, + # use it as the $ATMOS_BASE_PATH + if [[ -d "${GEODESIC_WORKDIR}/stacks" ]] && [[ -d "${GEODESIC_WORKDIR}/components" ]]; then + export ATMOS_BASE_PATH="${GEODESIC_WORKDIR}" + green "# Setting ATMOS_BASE_PATH to \"$ATMOS_BASE_PATH\" based on children of workdir" + return + fi + + # If $GEODESIC_WORKDIR is a descendent of either a "stacks" or "components" directory, + # use the parent of that directory as ATMOS_BASE_PATH + if [[ "${GEODESIC_WORKDIR}" =~ /(stacks|components)/ ]]; then + if [[ "${GEODESIC_WORKDIR}" =~ /stacks/ ]]; then + export ATMOS_BASE_PATH="${GEODESIC_WORKDIR%/stacks/*}" + else + export ATMOS_BASE_PATH="${GEODESIC_WORKDIR%/components/*}" + fi + green "# Setting ATMOS_BASE_PATH to \"$ATMOS_BASE_PATH\" based on parent of workdir" + return + fi + yellow "# No candidate for ATMOS_BASE_PATH found, leaving it unset" +} + +# Only configure ATMOS_BASE_PATH if we find an `atmos` executable, +# but otherwise leave the function available for the user to call explicitly. +# NOTE: If we start shipping `atmos` with Geodesic by default, change this to +# [[ -f /usr/local/etc/atmos/atmos.yaml ]] && _configure_atmos_base_path +command -v atmos >/dev/null && _configure_atmos_base_path && unset -f _configure_atmos_base_path diff --git a/rootfs/etc/profile.d/prompt.sh b/rootfs/etc/profile.d/prompt.sh index ffe18541b..862abc352 100755 --- a/rootfs/etc/profile.d/prompt.sh +++ b/rootfs/etc/profile.d/prompt.sh @@ -61,25 +61,36 @@ function geodesic_prompt() { plain) # 8859-1 codepoints: # '\[' and '\]' are bash prompt delimiters around non-printing characters - ASSUME_ROLE_ACTIVE_MARK="\["$(tput bold)$(tput setab 2)"\]»\["$(tput sgr0)"\] " # green - ASSUME_ROLE_INACTIVE_MARK=$'· ' - BLACK_RIGHTWARDS_ARROWHEAD=$'=> ' - BANNER_MARK=$'§ ' + [[ -z $ASSUME_ROLE_ACTIVE_MARK ]] && ASSUME_ROLE_ACTIVE_MARK="\["$(tput bold)$(tput setab 2)"\]»\["$(tput sgr0)"\]" # green + [[ -z $ASSUME_ROLE_INACTIVE_MARK ]] && ASSUME_ROLE_INACTIVE_MARK=$'·' + [[ -z $BLACK_RIGHTWARDS_ARROWHEAD ]] && BLACK_RIGHTWARDS_ARROWHEAD=$'=>' + [[ -z $BANNER_MARK ]] && BANNER_MARK=$'§' ;; unicode) # unicode - ASSUME_ROLE_ACTIVE_MARK=$'\u2705 ' # '✅' - ASSUME_ROLE_INACTIVE_MARK=$'\u274C ' # '❌' - BLACK_RIGHTWARDS_ARROWHEAD=$'\u27A4 ' # '➤', suggest '▶' may be present in more fonts - BANNER_MARK=$'\u29C9 ' # '⧉' + [[ -z $ASSUME_ROLE_ACTIVE_MARK ]] && ASSUME_ROLE_ACTIVE_MARK=$'\u2705' # '✅' + [[ -z $ASSUME_ROLE_INACTIVE_MARK ]] && ASSUME_ROLE_INACTIVE_MARK=$'\u274C' # '❌' + [[ -z $BLACK_RIGHTWARDS_ARROWHEAD ]] && BLACK_RIGHTWARDS_ARROWHEAD=$'\u27A4' # '➤', suggest '▶' may be present in more fonts + [[ -z $BANNER_MARK ]] && BANNER_MARK=$'\u29C9' # '⧉' + ;; + + fancy) + # Same as default, except for BLACK_RIGHTWARDS_ARROWHEAD, because the character used in the + # default set, Z NOTATION SCHEMA PIPING, is from the "Supplemental Mathematical Operators" Unicode block + # which is not included by default in the Ubuntu terminal font. + # See https://github.com/cloudposse/geodesic/issues/417 + [[ -z $ASSUME_ROLE_ACTIVE_MARK ]] && ASSUME_ROLE_ACTIVE_MARK=$'\x01'$(tput bold)$(tput setaf 2)$'\x02\u221a\x01'$(tput sgr0)$'\x02' # green bold '√' + [[ -z $ASSUME_ROLE_INACTIVE_MARK ]] && ASSUME_ROLE_INACTIVE_MARK=$'\x01'$(tput bold)$(tput setaf 1)$'\x02\u2717\x01'$(tput sgr0)$'\x02' # red bold '✗' + [[ -z $BLACK_RIGHTWARDS_ARROWHEAD ]] && BLACK_RIGHTWARDS_ARROWHEAD=$'\u27A4' # '➤' + [[ -z $BANNER_MARK ]] && BANNER_MARK='⧉' # \u29c9 TWO JOINED SQUARES ;; *) # default - # ASSUME_ROLE_ACTIVE_MARK=$' \x01'$(tput bold)$(tput setaf 2)$'\x02\u2713 \x01'$(tput sgr0)$'\x02' # green bold '✓' - ASSUME_ROLE_ACTIVE_MARK=$' \x01'$(tput bold)$(tput setaf 2)$'\x02\u221a \x01'$(tput sgr0)$'\x02' # green bold '√' - ASSUME_ROLE_INACTIVE_MARK=$' \x01'$(tput bold)$(tput setaf 1)$'\x02\u2717 \x01'$(tput sgr0)$'\x02' # red bold '✗' + # ASSUME_ROLE_ACTIVE_MARK=$'\x01'$(tput bold)$(tput setaf 2)$'\x02\u2713\x01'$(tput sgr0)$'\x02' # green bold '✓' + [[ -z $ASSUME_ROLE_ACTIVE_MARK ]] && ASSUME_ROLE_ACTIVE_MARK=$'\x01'$(tput bold)$(tput setaf 2)$'\x02\u221a\x01'$(tput sgr0)$'\x02' # green bold '√' + [[ -z $ASSUME_ROLE_INACTIVE_MARK ]] && ASSUME_ROLE_INACTIVE_MARK=$'\x01'$(tput bold)$(tput setaf 1)$'\x02\u2717\x01'$(tput sgr0)$'\x02' # red bold '✗' # Options for arrow per https://github.com/cloudposse/geodesic/issues/417#issuecomment-477836676 # '»' ($'\u00bb') RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK from the Latin-1 supplement Unicode block # '≫' ($'\u226b') MUCH GREATER-THAN and @@ -87,11 +98,15 @@ function geodesic_prompt() { # '➤' ($'\u27a4') BLACK RIGHTWARDS ARROWHEAD from the Dingbats Unicode block # '▶︎' ($'\u25b6\ufe0e') BLACK RIGHT-POINTING TRIANGLE which is sometimes presented as an emoji (as GitHub likes to) '▶️' # '⏩︎' ($'\u23e9\ufe0e') BLACK RIGHT-POINTING DOUBLE TRIANGLE - BLACK_RIGHTWARDS_ARROWHEAD=$'\u2a20 ' # '⨠' Z NOTATION SCHEMA PIPING - BANNER_MARK='⧉ ' + [[ -z $BLACK_RIGHTWARDS_ARROWHEAD ]] && BLACK_RIGHTWARDS_ARROWHEAD=$'\u2a20' # '⨠' Z NOTATION SCHEMA PIPING + [[ -z $BANNER_MARK ]] && BANNER_MARK='⧉' # \u29c9 TWO JOINED SQUARES ;; esac + # "(HOST)" with "HOST" in bold red. Only test for unset ("-") instead of unset or null (":-") so that + # the feature can be suppressed by setting PROMPT_HOST_MARK to null. + [[ -z $PROMPT_HOST_MARK ]] && PROMPT_HOST_MARK="${PROMPT_HOST_MARK-$'(\x01'$(tput bold)$(tput setaf 1)$'\x02HOST\x01'$(tput sgr0)$'\x02)'}" + local level_prompt case $SHLVL in 1) level_prompt='.' ;; @@ -123,13 +138,13 @@ function geodesic_prompt() { done local dir_prompt - dir_prompt="${STATUS}${level_prompt} " - if [[ $(pwd -P) =~ ^/localhost/ ]]; then - dir_prompt+="${ROLE_PROMPT} ("$'\x01'$(tput bold)$(tput setaf 1)$'\x02HOST\x01'$(tput sgr0)$'\x02'") \W " + dir_prompt=" ${STATUS} ${level_prompt} " + if [[ -n $PROMPT_HOST_MARK ]] && file_on_host "$(pwd -P)"; then + dir_prompt+="${ROLE_PROMPT} ${PROMPT_HOST_MARK} \W " else dir_prompt+="${ROLE_PROMPT} \W " fi - dir_prompt+=$'${GEODISIC_PROMPT_GLYPHS-$BLACK_RIGHTWARDS_ARROWHEAD}' + dir_prompt+=$'${GEODESIC_PROMPT_GLYPHS-${BLACK_RIGHTWARDS_ARROWHEAD} }' update_terraform_prompt local old_kube_ps1_prefix="$KUBE_PS1_PREFIX" @@ -143,7 +158,7 @@ function geodesic_prompt() { tf_mark="${ASSUME_ROLE_ACTIVE_MARK}" fi if [[ -n ${GEODESIC_TF_PROMPT_LINE} ]]; then - tf_prompt="${tf_mark}${GEODESIC_TF_PROMPT_LINE}\n" + tf_prompt=" ${tf_mark} ${GEODESIC_TF_PROMPT_LINE}\n" fi if [[ $GEODESIC_TERRAFORM_WORKSPACE_PROMPT_ENABLED == "true" ]]; then KUBE_PS1_PREFIX="$(yellow "cluster:")(" @@ -154,7 +169,8 @@ function geodesic_prompt() { fi if [ -n "${BANNER}" ]; then - PS1=$' ${BANNER_MARK}'" ${BANNER} $(kube_ps1)${secrets_active}\n${tf_prompt}${dir_prompt}" + # Intentional 2 spaces between banner mark and banner in order to offset it from level prompt + PS1=$' ${BANNER_MARK}'" ${BANNER} $(kube_ps1)${secrets_active}\n${tf_prompt}${dir_prompt}" else PS1="${tf_prompt}${dir_prompt}" fi diff --git a/rootfs/templates/wrapper b/rootfs/templates/wrapper index e5bfb9577..2814b863e 100755 --- a/rootfs/templates/wrapper +++ b/rootfs/templates/wrapper @@ -6,8 +6,7 @@ set -o pipefail # Geodesic Settings export GEODESIC_PORT=${GEODESIC_PORT:-$((30000 + $$ % 30000))} -# If this env var is unset, set it to the current directory without the home dir -export GEODESIC_WORKDIR=${GEODESIC_WORKDIR:-/localhost/${PWD#$HOME/}} +export GEODESIC_HOST_CWD=$(pwd -P 2>/dev/null || pwd) readonly OS=$(uname -s) @@ -156,12 +155,15 @@ function use() { if [ "${local_home}" == "/localhost" ]; then echo "WARNING: not mounting ${local_home} because it conflicts with geodesic" else - echo "# Mounting ${local_home} into container" - DOCKER_ARGS+=(--volume=${local_home}:/localhost) - DOCKER_ARGS+=(--env LOCAL_HOME=${local_home}) + echo "# Mounting ${local_home} into container with workdir ${GEODESIC_HOST_CWD}" + DOCKER_ARGS+=( + --volume="${local_home}:/localhost" + --env LOCAL_HOME="${local_home}" + ) fi - DOCKER_ARGS+=(--privileged + DOCKER_ARGS+=( + --privileged --publish ${GEODESIC_PORT}:${GEODESIC_PORT} --name "${DOCKER_NAME}" --rm @@ -169,7 +171,8 @@ function use() { --env DOCKER_IMAGE="${DOCKER_IMAGE%:*}" --env DOCKER_NAME="${DOCKER_NAME}" --env DOCKER_TAG="${DOCKER_TAG}" - --workdir "${GEODESIC_WORKDIR}") + --env GEODESIC_HOST_CWD="${GEODESIC_HOST_CWD}" + ) trap run_exit_hooks EXIT # the extra curly braces around .ID are because this file goes through go template substitution local before being installed as a shell script @@ -179,7 +182,7 @@ function use() { if [ $# -eq 0 ]; then set -- "/bin/bash" "-l" "$@" fi - docker exec -it "${DOCKER_NAME}" $* + docker exec -it --env GEODESIC_HOST_CWD="${GEODESIC_HOST_CWD}" "${DOCKER_NAME}" $* else echo "# Starting new ${DOCKER_NAME} session from ${DOCKER_IMAGE}" echo "# Exposing port ${GEODESIC_PORT}"