-
Notifications
You must be signed in to change notification settings - Fork 57
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from gruntwork-io/v1
Make our installer scripts open source
- Loading branch information
Showing
3 changed files
with
488 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
# Gruntwork Installer | ||
|
||
[Gruntwork Script Modules](https://github.com/gruntwork-io/script-modules) is a private repo that contains scripts and | ||
applications developed by [Gruntwork](http://www.gruntwork.io) for common infrastructure tasks such as setting up | ||
continuous integration, monitoring, log aggregation, and SSH access. This repo contains provides a script called | ||
`gruntwork-install` that makes it as easy to install the Gruntwork Script Modules as using apt-get, brew, or yum. | ||
|
||
For example, in your Packer and Docker templates, you can use `gruntwork-install` as follows: | ||
|
||
```bash | ||
gruntwork-install --module-name 'vault-ssh-helper' --tag '0.0.3' | ||
``` | ||
|
||
## Installing gruntwork-install | ||
|
||
```bash | ||
curl -Ls https://raw.githubusercontent.com/gruntwork-io/gruntwork-installer/master/bootstrap-gruntwork-installer.sh | bash -s --version=0.0.1 | ||
``` | ||
|
||
Notice the `--version` parameter at the end where you specify which version of `gruntwork-install` to install. See the | ||
[releases](/releases) page for all available versions. | ||
|
||
For paranoid security folks, see [is it safe to pipe URLs into bash?](#is-it-safe-to-pipe-urls-into-bash) below. | ||
|
||
## Using gruntwork-install | ||
|
||
#### Authentication | ||
|
||
Since the [Script Modules](https://github.com/gruntwork-io/script-modules) repo is private, you must set your | ||
[GitHub access token](https://help.github.com/articles/creating-an-access-token-for-command-line-use/) as the | ||
environment variable `GITHUB_OAUTH_TOKEN` so `gruntwork-install` can use it to access the repo: | ||
|
||
```bash | ||
export GITHUB_OAUTH_TOKEN="..." | ||
``` | ||
|
||
#### Options | ||
|
||
Once that environment variable is set, you can run `gruntwork-install` with the following options: | ||
|
||
* `--module-name`: Required. The name of the Script Module to install. Can be any folder within the `modules` directory | ||
of the [Script Modules Repo](https://github.com/gruntwork-io/script-modules). | ||
* `--tag`: Required. The version of the Script Module to install. Follows the syntax described at [Fetch Version | ||
Constraint Operators](https://github.com/gruntwork-io/fetch#version-constraint-operators). | ||
* `--branch`: Optional. Download the latest commit from this branch. This is an alternative to `--tag` for development | ||
purposes. | ||
* `--module-param`: Optional. A key-value pair of the format `key=value` you wish to pass to the module as a parameter. | ||
May be used multiple times. See the documentation for each module to find out what parameters it accepts. | ||
* `--help`: Optional. Show the help text and exit. | ||
|
||
#### Examples | ||
|
||
Here is how you could use `gruntwork-install` to install the `vault-ssh-helper` module, version `0.0.3`: | ||
|
||
```bash | ||
gruntwork-install --module-name 'vault-ssh-helper' --tag '0.0.3' | ||
``` | ||
|
||
And here is an example of using `--module-param` to pass two custom parameters to the `vault-ssh-helper` module: | ||
|
||
```bash | ||
gruntwork-install --module-name 'vault-ssh-helper' --tag '0.0.3' --module-param 'install-dir=/opt/vault-ssh-helper' --module-param 'owner=ubuntu' | ||
``` | ||
|
||
And finally, to put all the pieces together, here is an example of a Packer template that installs `gruntwork-install` | ||
and then uses it to install several modules: | ||
|
||
```json | ||
{ | ||
"variables": { | ||
"github_auth_token": "{{env `GITHUB_OAUTH_TOKEN`}}" | ||
}, | ||
"builders": [{ | ||
"ami_name": "gruntwork-install-example-{{isotime | clean_ami_name}}", | ||
"instance_type": "t2.micro", | ||
"region": "us-east-1", | ||
"type": "amazon-ebs", | ||
"source_ami": "ami-fce3c696", | ||
"ssh_username": "ubuntu" | ||
}], | ||
"provisioners": [{ | ||
"type": "shell", | ||
"inline": "curl -Ls https://raw.githubusercontent.com/gruntwork-io/gruntwork-installer/master/bootstrap-gruntwork-installer.sh | bash -s --version=0.0.1" | ||
},{ | ||
"type": "shell", | ||
"inline": [ | ||
"gruntwork-install --module-name 'vault-ssh-helper' --tag '~>0.0.4' --module-param 'install-dir=/opt/vault-ssh-helper' --module-param 'owner=ubuntu'", | ||
"gruntwork-install --module-name 'cloudwatch-log-aggregation' --tag '~>0.0.4'", | ||
"gruntwork-install --module-name 'build-helpers' --tag '~>0.0.4'" | ||
], | ||
"environment_vars": [ | ||
"GITHUB_OAUTH_TOKEN={{user `github_auth_token`}}" | ||
] | ||
}] | ||
} | ||
``` | ||
|
||
## Is it safe to pipe URLs into bash? | ||
|
||
Are you worried that our install instructions tell you to pipe a URL into bash? Although this approach has seen some | ||
[backlash](https://news.ycombinator.com/item?id=6650987), we believe that the convenience of a one-line install | ||
outweighs the minimal security risks. Below is a brief discussion of the most commonly discussed risks and what you can | ||
do about them. | ||
|
||
#### Risk #1: You don't know what the script is doing, so you shouldn't blindly execute it. | ||
|
||
This is true of *all* installers. For example, have you ever inspected the install code before running `apt-get install` | ||
or `brew install` or double cliking a `.dmg` or `.exe` file? If anything, a shell script is the most transparent | ||
installer out there, as it's one of the few that allows you to inspect the code (feel free to do so, as this script is | ||
open source!). The reality is that you either trust the developer or you don't. And eventually, you automate the | ||
install process anyway, at which point manual inspection isn't a possibility anyway. | ||
|
||
#### Risk #2: The download URL could be hijacked for malicious code. | ||
|
||
This is unlikely, as it is an https URL, and your download program (e.g. `curl`) should be verifying SSL certs. That | ||
said, Certificate Authorities have been hacked in the past, and if that is a major concern for you, feel free to copy | ||
the bootstrap code into your own codebase and execute it from there. | ||
|
||
#### Risk #3: The script may not download fully and executing it could cause catastrophic errors. | ||
|
||
We wrote our bootstrap script as a series of bash functions that are only executed by the very last line of the script. | ||
Therefore, if the script doesn't fully download, the worst that'll happen when you execute it is a harmless syntax | ||
error. | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
#!/bin/bash | ||
# | ||
# A bootstrap script to install the Gruntwork Installer. | ||
# | ||
# Why: | ||
# | ||
# The goal of the Gruntwork Installer is to make make installing Gruntwork Script Modules feel as easy as installing a | ||
# package using apt-get, brew, or yum. However, something has to install the Gruntwork Installer first. One option is | ||
# for each Gruntwork client to do so manually, which would basically entail copying and pasting all the code below. | ||
# This is tedious and would give us no good way to push updates to this bootstrap script. | ||
# | ||
# So instead, we recommend that clients use this tiny bootstrap script as a one-liner: | ||
# | ||
# curl -Ls https://raw.githubusercontent.com/gruntwork-io/gruntwork-installer/master/bootstrap-gruntwork-installer.sh | bash -s --version=0.0.12 | ||
# | ||
# You can copy this one-liner into your Packer and Docker templates and immediately after, start using the | ||
# gruntwork-install command. | ||
|
||
set -e | ||
|
||
readonly DEFAULT_FETCH_VERSION="v0.0.3" | ||
readonly FETCH_DOWNLOAD_URL_BASE="https://github.com/gruntwork-io/fetch/releases/download" | ||
readonly FETCH_INSTALL_PATH="/usr/local/bin/fetch" | ||
|
||
readonly GRUNTWORK_INSTALLER_DOWNLOAD_URL_BASE="https://raw.githubusercontent.com/gruntwork-io/gruntwork-installer" | ||
readonly GRUNTWORK_INSTALLER_INSTALL_PATH="/usr/local/bin/gruntwork-install" | ||
readonly GRUNTWORK_INSTALLER_SCRIPT_NAME="gruntwork-install" | ||
|
||
function print_usage { | ||
echo | ||
echo "Usage: bootstrap-gruntwork-installer.sh [OPTIONS]" | ||
echo | ||
echo "A bootstrap script to install the Gruntwork Installer ($GRUNTWORK_INSTALLER_SCRIPT_NAME)." | ||
echo | ||
echo "Options:" | ||
echo | ||
echo -e " --version\t\tRequired. The version of $GRUNTWORK_INSTALLER_SCRIPT_NAME to install (e.g. 0.0.3)." | ||
echo -e " --fetch-version\tOptional. The version of fetch to install. Default: $DEFAULT_FETCH_VERSION." | ||
echo | ||
echo "Examples:" | ||
echo | ||
echo " Install version 0.0.3:" | ||
echo " bootstrap-gruntwork-installer.sh --version=0.0.3" | ||
echo | ||
echo " One-liner to download this bootstrap script from GitHub and run it to install version 0.0.3:" | ||
echo " curl -Ls https://raw.githubusercontent.com/gruntwork-io/gruntwork-installer/master/bootstrap-gruntwork-installer.sh | bash -s --version=0.0.3" | ||
} | ||
|
||
function command_exists { | ||
local readonly cmd="$1" | ||
type "$cmd" > /dev/null 2>&1 | ||
} | ||
|
||
function download_url_to_file { | ||
local readonly url="$1" | ||
local readonly file="$2" | ||
|
||
echo "Downloading $url to $file" | ||
if $(command_exists "curl"); then | ||
local readonly status_code=$(curl -L -s -w '%{http_code}' -o "$file" "$url") | ||
if [[ "$status_code" != "200" ]]; then | ||
echo "ERROR: Expected status code 200 but got $status_code when downloading $url" | ||
exit 1 | ||
fi | ||
else | ||
echo "ERROR: curl is not installed. Cannot download $url." | ||
exit 1 | ||
fi | ||
} | ||
|
||
function string_contains { | ||
local readonly str="$1" | ||
local readonly contains="$2" | ||
|
||
[[ "$str" == *"$contains"* ]] | ||
} | ||
# http://stackoverflow.com/a/2264537/483528 | ||
function to_lower_case { | ||
tr '[:upper:]' '[:lower:]' | ||
} | ||
|
||
function get_os_name { | ||
uname | to_lower_case | ||
} | ||
|
||
function get_os_arch { | ||
uname -m | ||
} | ||
|
||
function get_os_arch_gox_format { | ||
local readonly arch=$(get_os_arch) | ||
|
||
if $(string_contains "$arch" "64"); then | ||
echo "amd64" | ||
elif $(string_contains "$arch" "386"); then | ||
echo "386" | ||
elif $(string_contains "$arch" "arm"); then | ||
echo "arm" | ||
fi | ||
} | ||
|
||
function download_and_install { | ||
local readonly url="$1" | ||
local readonly install_path="$2" | ||
|
||
download_url_to_file "$url" "$install_path" | ||
chmod 0755 "$install_path" | ||
} | ||
|
||
function install_fetch { | ||
local readonly install_path="$1" | ||
local readonly version="$2" | ||
|
||
local readonly os=$(get_os_name) | ||
local readonly os_arch=$(get_os_arch_gox_format) | ||
|
||
if [[ -z "$os_arch" ]]; then | ||
echo "ERROR: Unrecognized OS architecture: $(get_os_arch)" | ||
exit 1 | ||
fi | ||
|
||
echo "Installing fetch version $version to $install_path" | ||
local readonly url="${FETCH_DOWNLOAD_URL_BASE}/${version}/fetch_${os}_${os_arch}" | ||
download_and_install "$url" "$install_path" | ||
} | ||
|
||
function install_gruntwork_installer { | ||
local readonly install_path="$1" | ||
local readonly version="$2" | ||
|
||
echo "Installing $GRUNTWORK_INSTALLER_SCRIPT_NAME version $version to $install_path" | ||
local readonly url="${GRUNTWORK_INSTALLER_DOWNLOAD_URL_BASE}/${version}/${GRUNTWORK_INSTALLER_SCRIPT_NAME}" | ||
download_and_install "$url" "$install_path" | ||
} | ||
|
||
function assert_not_empty { | ||
local readonly arg_name="$1" | ||
local readonly arg_value="$2" | ||
|
||
if [[ -z "$arg_value" ]]; then | ||
echo "ERROR: The value for '$arg_name' cannot be empty" | ||
print_usage | ||
exit 1 | ||
fi | ||
} | ||
|
||
function bootstrap { | ||
local fetch_version="$DEFAULT_FETCH_VERSION" | ||
local installer_version="" | ||
|
||
while [[ $# > 0 ]]; do | ||
local key="$1" | ||
|
||
case "$key" in | ||
--version) | ||
installer_version="$2" | ||
shift | ||
;; | ||
--fetch-version) | ||
fetch_version="$2" | ||
shift | ||
;; | ||
--help) | ||
print_usage | ||
exit | ||
;; | ||
*) | ||
echo "ERROR: Unrecognized option: $key" | ||
print_usage | ||
exit 1 | ||
;; | ||
esac | ||
|
||
shift | ||
done | ||
|
||
assert_not_empty "--version" "$installer_version" | ||
assert_not_empty "--fetch-version" "$fetch_version" | ||
|
||
echo "Installing $GRUNTWORK_INSTALLER_SCRIPT_NAME..." | ||
install_fetch "$FETCH_INSTALL_PATH" "$fetch_version" | ||
install_gruntwork_installer "$GRUNTWORK_INSTALLER_INSTALL_PATH" "$installer_version" | ||
echo "Success!" | ||
} | ||
|
||
bootstrap "$@" |
Oops, something went wrong.