Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Start in host CWD, autoconfigure ATMOS_BASE_PATH #756

Merged
merged 9 commits into from
Jan 23, 2022
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

<!-- markdownlint-disable -->
# 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)
<!-- markdownlint-restore -->
Expand Down Expand Up @@ -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.
Expand All @@ -66,7 +66,6 @@ It's 100% Open Source and licensed under the [APACHE2](LICENSE).




## Screenshots


Expand Down Expand Up @@ -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


Expand Down Expand Up @@ -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.
Expand All @@ -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.
Expand Down Expand Up @@ -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)



Expand Down
7 changes: 0 additions & 7 deletions rootfs/etc/init.d/atmos.sh

This file was deleted.

60 changes: 60 additions & 0 deletions rootfs/etc/profile.d/_workdir.sh
Original file line number Diff line number Diff line change
@@ -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
Nuru marked this conversation as resolved.
Show resolved Hide resolved
}

# 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
38 changes: 38 additions & 0 deletions rootfs/etc/profile.d/atmos.sh
Original file line number Diff line number Diff line change
@@ -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
Comment on lines +5 to +6
Copy link

@korenyoni korenyoni Jan 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't this be part of the same if conditional? i.e. [[ -n $ATMOS_BASE_PATH ]] && [[ $SHLVL == 1 ]] ?

Also I think there should be an inline comment explaining why we are specifically testing for the number of shell levels.

EDIT: I see that they do need to be nested. But my comment on SHLVL still applies.

Copy link
Sponsor Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a classic example of a bad comment:

x = x + 1   // Add 1 to x

I didn't put a comment in about SHLVL because it seems to me it would be too much like that kind of bad comment.

# Only output status in top level shell
if [[ $SHLVL == 1 ]]; then

The more useful comment would be about the bigger architectural design choice, but that would be long and does not belong in this bit of code. Since you asked, I will explain here in this comment.

The startup scripts (everything in profile.d) are responsible for a lot of the behavior of the interactive shell. Every time we spawn an interactive subshell, such as with assume-role, we run all these scripts again in the subshell to set it up. However, the startup messages are intended to expose configuration details of the Docker container or, if you will, the Geodesic session, more generally, and we do not want to repeat them when starting up a subshell with assume-role because (1) at that point they are not news and (2) its unnecessarily distracting. If you look around, you will find test for $SHLVL == 1 all over the scripts in profile.d.

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"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Children of workdir" is a little vague outside of the context, especially to a Geodesic user who isn't reading the source of this script.

Here's a quick suggestion, but maybe word it differently.

Suggested change
green "# Setting ATMOS_BASE_PATH to \"$ATMOS_BASE_PATH\" based on children of workdir"
green "# Atmos base path automatically determined to be current workdir; setting ATMOS_BASE_PATH to \"$ATMOS_BASE_PATH\""

Copy link
Sponsor Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is printed out is in a form and style consistent with the other startup output from Geodesic:

# Mounting /Users/user into container
# Starting new geodesic session from cloudposse/geodesic:debian
# Exposing port 32380
# Setting ATMOS_BASE_PATH to "/localhost/source/geodesic" based on children of workdir

The fact that "children of workdir" is a bit cryptic is OK with me. The purpose of the message is not to explain to the user how the setting was derived, as that just takes too much verbiage for a startup message. The point is to distinguish which criteria were used in setting ATMOS_BASE_PATH so if there is a problem, we can more easily diagnose the cause.

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"
Nuru marked this conversation as resolved.
Show resolved Hide resolved
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
54 changes: 35 additions & 19 deletions rootfs/etc/profile.d/prompt.sh
Original file line number Diff line number Diff line change
Expand Up @@ -61,37 +61,52 @@ 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
# '⋙' ($'\u22d9') VERY MUCH GREATER-THAN which are from the Mathematical Operators Unicode block
# '➤' ($'\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='.' ;;
Expand Down Expand Up @@ -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"
Expand All @@ -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:")("
Expand All @@ -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
Expand Down
19 changes: 11 additions & 8 deletions rootfs/templates/wrapper
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -156,20 +155,24 @@ 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
--env GEODESIC_PORT=${GEODESIC_PORT}
--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
Expand All @@ -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}"
Expand Down