Created
August 1, 2017 05:41
-
-
Save double-z/ff7c60613712f81a7c4bb7f07256daad to your computer and use it in GitHub Desktop.
This file contains hidden or 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
#!/bin/bash | |
# | |
# BASH script to install DC/OS on a node | |
# | |
# Usage: | |
# | |
# dcos_install.sh <role>... | |
# | |
# | |
# Metadata: | |
# dcos image commit: af6ddc2f5e95b1c1d9bd9fd3d3ef1891928136b9 | |
# generation date: 2017-07-31 22:46:11.112364 | |
# | |
# Copyright 2016 Mesosphere, Inc. | |
# | |
# Licensed under the Apache License, Version 2.0 (the "License"); | |
# you may not use this file except in compliance with the License. | |
# You may obtain a copy of the License at | |
# | |
# http://www.apache.org/licenses/LICENSE-2.0 | |
# | |
# Unless required by applicable law or agreed to in writing, software | |
# distributed under the License is distributed on an "AS IS" BASIS, | |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
# See the License for the specific language governing permissions and | |
# limitations under the License. | |
set -o errexit -o nounset -o pipefail | |
declare -i OVERALL_RC=0 | |
declare -i PREFLIGHT_ONLY=0 | |
declare -i DISABLE_PREFLIGHT=0 | |
declare -i SYSTEMCTL_NO_BLOCK=0 | |
declare ROLES="" | |
declare RED="" | |
declare BOLD="" | |
declare NORMAL="" | |
# Check if this is a terminal, and if colors are supported, set some basic | |
# colors for outputs | |
if [ -t 1 ]; then | |
colors_supported=$(tput colors) | |
if [[ $colors_supported -ge 8 ]]; then | |
RED='\e[1;31m' | |
BOLD='\e[1m' | |
NORMAL='\e[0m' | |
fi | |
fi | |
# Setup getopt argument parser | |
ARGS=$(getopt -o dph --long "disable-preflight,preflight-only,help,no-block-dcos-setup" -n "$(basename "$0")" -- "$@") | |
if [[ $EUID -ne 0 ]]; then | |
echo "This script must be run as root" 1>&2 | |
exit 1 | |
fi | |
function setup_directories() { | |
echo -e "Creating directories under /etc/mesosphere" | |
mkdir -p /etc/mesosphere/roles | |
mkdir -p /etc/mesosphere/setup-flags | |
} | |
function setup_dcos_roles() { | |
# Set DC/OS roles | |
for role in $ROLES | |
do | |
echo "Creating role file for ${role}" | |
touch "/etc/mesosphere/roles/$role" | |
done | |
} | |
# Set DC/OS machine configuration | |
function configure_dcos() { | |
echo -e 'Configuring DC/OS' | |
mkdir -p `dirname /etc/mesosphere/setup-flags/repository-url` | |
cat <<'EOF' > "/etc/mesosphere/setup-flags/repository-url" | |
http://192.168.65.50 | |
EOF | |
chmod 0644 /etc/mesosphere/setup-flags/repository-url | |
mkdir -p `dirname /etc/mesosphere/setup-flags/cluster-packages.json` | |
cat <<'EOF' > "/etc/mesosphere/setup-flags/cluster-packages.json" | |
["3dt--caa28740ba55b7f6de50ab574e91a3f087701e7a", "adminrouter--a4c1e2c311b66185e3fc26350ef55086a4434b3c", "avro-cpp--b705160facaef4071e6e1999d4a3f10b6bebddfc", "boost-libs--2015ccb58fb756f61c02ee6aa05cc1e27459a9ec", "bootstrap--d8cdde7d671f2ef25087c2941e28d60049f168dd", "boto--6344d31eef082c7bd13259b17034ea7b5c34aedf", "check-time--be7d0ba757ec87f9965378fee7c76a6ee5ae996d", "cni--e48337da39a8cd379414acfe0da52a9226a10d24", "cosmos--e51eff0287fa62a5c3f119bf49596f616eafad72", "curl--fc3486c43f98e63f9b12675f1356e8fe842f26b0", "dcos-config--setup_81e0aea0bfb0988c93044950f259bc64beec9e17", "dcos-history--f059725ebe14a980c1b7d889055d78c56720d737", "dcos-image--e42f099fbe4d35adb7ae10316e6e88f308a08397", "dcos-image-deps--83584fd868e5b470f7cf754424a9a75b328e9b68", "dcos-integration-test--3acd68afab37740ef5e19c1658f7c7d6e3ae073a", "dcos-log--4d630df863228f38c6333e44670b4c4b20a74832", "dcos-metadata--setup_81e0aea0bfb0988c93044950f259bc64beec9e17", "dcos-metrics--3f9c56b0c3aef016427b723a7d2e4e6afdf9c04e", "dcos-oauth--0079529da183c0f23a06d2b069721b6fa6cc7b52", "dcos-signal--5633dc8da7e864cb34e3d29ed13e6756c7a6df94", "dcos-ui--7693dca6567e31cc107b765ce6612ae48a417528", "dnspython--0f833eb9a8abeba3179b43f3a200a8cd42d3795a", "docker-gc--59a98ed6446a084bf74e4ff4b8e3479f59ea8528", "dvdcli--5374dd4ffb519f1dcefdec89b2247e3404f2e2e3", "erlang--a9ee2530357a3301e53056b36a93420847b339a3", "exhibitor--6be3f543dbed3abbc22218fd703e52609bc49a67", "flask--26d1bcdb2d1c3dcf1d2c03bc0d4f29c86d321b21", "java--cd5e921ce66b0d3303883c06d73a657314044304", "libevent--208be855d2be29c9271a7bd6c04723ff79946e02", "libffi--83ce3bd7eda2ef089e57efd2bc16c144d5a1f094", "libsodium--9ff915db08c6bba7d6738af5084e782b13c84bf8", "logrotate--7f7bc4416d3ad101d0c5218872858483b516be07", "marathon--8f59f94aaa21adbe497e0f49a8d0bb41515968db", "mesos--8672838b73e866c786446d1a4d7afce701f7df62", "mesos-dns--f8c80e9bffa1fe238711f82fa06006de8715cceb", "mesos-modules--6680e631c9689dd33f1115bdae3d31fafe70051f", "metronome--6eafabd93182e8844c72ce19690e93d2b7926931", "navstar--0b141af667446bbe42069fbdba130276f872061c", "ncurses--d889894b71aa1a5b311bafef0e85479025b4dacb", "octarine--dada18ca28c1b7948ed895580cc0a59d5b3c5583", "openssl--b01a32a42e3ccba52b417276e9509a441e1d4a82", "pkgpanda-api--1acf427af3dd51b7bd56176bce3e8a6580489219", "pkgpanda-role--f8a749a4a821476ad2ef7e9dd9d12b6a8c4643a4", "pytest--78aee3e58a049cdab0d266af74f77d658b360b4f", "python--b7a144a49577a223d37d447c568f51330ee95390", "python-azure-mgmt-resource--03c05550f43b0e7a4455c33fe43b0deb755d87f0", "python-cryptography--4184767c68e48801dd394072cb370c610a05029d", "python-dateutil--fdc6ff929f65dd0918cf75a9ad56704683d31781", "python-docopt--beba78faa13e5bf4c52393b4b82d81f3c391aa65", "python-gunicorn--a537f95661fb2689c52fe12510eb0d01cb83af60", "python-isodate--40d378c688e6badfd16676dd8b51b742bfebc8d5", "python-jinja2--7450f5ae5a822f63f7a58c717207be0456df51ed", "python-kazoo--cb7ce13a1068cd82dd84ea0de32b529a760a4bdd", "python-markupsafe--dd46d2a3c58611656a235f96d4adc51b2a7a590e", "python-passlib--802ec3605c0b82428fedba60983b1bafaa036bb8", "python-pyyaml--81dd44cc4a24db7cefa7016c6586a131acf279c3", "python-requests--1b2cadbd3811cc0c2ee235ce927e13ea1d6af41d", "python-retrying--eb7b8bac133f50492b1e1349cbe77c3e38bd02c3", "python-tox--07244f8a939a10353634c952c6d88ec4a3c05736", "rexray--f07795e2c10f9a1a27de9d8e67ab171029db2e1d", "six--f06424b68523c4dfa2a7c3e7475d479f3d361e42", "spartan--daba6f5a190e67874b3aa852601ba039ecbab039", "strace--7d01796d64994451c1b2b82d161a335cbe90569b", "teamcity-messages--e623a4d86eb3a8d199cefcc240dd4c5460cb2962", "toybox--f235594ab8ea9a2864ee72abe86723d76f92e848"] | |
EOF | |
chmod 0644 /etc/mesosphere/setup-flags/cluster-packages.json | |
mkdir -p `dirname /etc/systemd/journald.conf.d/dcos.conf` | |
cat <<'EOF' > "/etc/systemd/journald.conf.d/dcos.conf" | |
[Journal] | |
MaxLevelConsole=warning | |
RateLimitInterval=1s | |
RateLimitBurst=20000 | |
EOF | |
chmod 0644 /etc/systemd/journald.conf.d/dcos.conf | |
mkdir -p `dirname /etc/rexray/config.yml` | |
cat <<'EOF' > "/etc/rexray/config.yml" | |
rexray: | |
loglevel: info | |
modules: | |
default-admin: | |
host: tcp://127.0.0.1:61003 | |
default-docker: | |
disabled: true | |
EOF | |
chmod 0644 /etc/rexray/config.yml | |
} | |
# Install the DC/OS services, start DC/OS | |
function setup_and_start_services() { | |
echo -e 'Setting and starting DC/OS' | |
mkdir -p `dirname /etc/systemd/system/dcos-link-env.service` | |
cat <<'EOF' > "/etc/systemd/system/dcos-link-env.service" | |
[Unit] | |
Before=dcos.target | |
[Service] | |
Type=oneshot | |
StandardOutput=journal+console | |
StandardError=journal+console | |
ExecStartPre=/usr/bin/mkdir -p /etc/profile.d | |
ExecStart=/usr/bin/ln -sf /opt/mesosphere/bin/add_dcos_path.sh /etc/profile.d/dcos.sh | |
EOF | |
chmod 0644 /etc/systemd/system/dcos-link-env.service | |
mkdir -p `dirname /etc/systemd/system/dcos-download.service` | |
cat <<'EOF' > "/etc/systemd/system/dcos-download.service" | |
[Unit] | |
Description=Pkgpanda: Download DC/OS to this host. | |
After=network-online.target | |
Wants=network-online.target | |
ConditionPathExists=!/opt/mesosphere/ | |
[Service] | |
Type=oneshot | |
StandardOutput=journal+console | |
StandardError=journal+console | |
ExecStartPre=/usr/bin/curl --keepalive-time 2 -fLsSv --retry 20 -Y 100000 -y 60 -o /tmp/bootstrap.tar.xz http://192.168.65.50/bootstrap/79a0dfe0944948a33ab75f6e62335f166e117f3d.bootstrap.tar.xz | |
ExecStartPre=/usr/bin/mkdir -p /opt/mesosphere | |
ExecStart=/usr/bin/tar -axf /tmp/bootstrap.tar.xz -C /opt/mesosphere | |
ExecStartPost=-/usr/bin/rm -f /tmp/bootstrap.tar.xz | |
EOF | |
chmod 0644 /etc/systemd/system/dcos-download.service | |
mkdir -p `dirname /etc/systemd/system/dcos-setup.service` | |
cat <<'EOF' > "/etc/systemd/system/dcos-setup.service" | |
[Unit] | |
Description=Pkgpanda: Specialize DC/OS for this host. | |
Requires=dcos-download.service | |
After=dcos-download.service | |
[Service] | |
Type=oneshot | |
StandardOutput=journal+console | |
StandardError=journal+console | |
EnvironmentFile=/opt/mesosphere/environment | |
ExecStart=/opt/mesosphere/bin/pkgpanda setup --no-block-systemd | |
[Install] | |
WantedBy=multi-user.target | |
EOF | |
chmod 0644 /etc/systemd/system/dcos-setup.service | |
systemctl restart systemd-journald | |
systemctl restart docker | |
systemctl start dcos-link-env | |
systemctl enable dcos-setup | |
if (( $SYSTEMCTL_NO_BLOCK == 1 )); then | |
systemctl start dcos-setup --no-block | |
else | |
systemctl start dcos-setup | |
fi | |
} | |
set +e | |
declare -i DISABLE_VERSION_CHECK=0 | |
# check if sort -V works | |
function check_sort_capability() { | |
$( command -v sort >/dev/null 2>&1 || exit 1 ) | |
RC1=$? | |
$( echo '1' | sort -V >/dev/null 2>&1 ) | |
RC2=$? | |
if [[ "$RC1" -eq "1" || "$RC2" -eq "2" ]]; then | |
echo -e "${RED}Disabling version checking as sort -V is not available${NORMAL}" | |
DISABLE_VERSION_CHECK=1 | |
fi | |
} | |
function version_gt() { | |
# sort -V does version-aware sort | |
HIGHEST_VERSION="$(echo "$@" | tr " " " | |
" | sort -V | tail -n 1)" | |
test $HIGHEST_VERSION == "$1" | |
} | |
function print_status() { | |
CODE_TO_TEST=$1 | |
EXTRA_TEXT=${2:-} | |
if [[ $CODE_TO_TEST == 0 ]]; then | |
echo -e "${BOLD}PASS $EXTRA_TEXT${NORMAL}" | |
else | |
echo -e "${RED}FAIL $EXTRA_TEXT${NORMAL}" | |
fi | |
} | |
function check_command_exists() { | |
COMMAND=$1 | |
DISPLAY_NAME=${2:-$COMMAND} | |
echo -e -n "Checking if $DISPLAY_NAME is installed and in PATH: " | |
$( command -v $COMMAND >/dev/null 2>&1 || exit 1 ) | |
RC=$? | |
print_status $RC | |
(( OVERALL_RC += $RC )) | |
return $RC | |
} | |
function check_version() { | |
COMMAND_NAME=$1 | |
VERSION_ATLEAST=$2 | |
COMMAND_VERSION=$3 | |
DISPLAY_NAME=${4:-$COMMAND} | |
echo -e -n "Checking $DISPLAY_NAME version requirement (>= $VERSION_ATLEAST): " | |
version_gt $COMMAND_VERSION $VERSION_ATLEAST | |
RC=$? | |
print_status $RC "${NORMAL}($COMMAND_VERSION)" | |
(( OVERALL_RC += $RC )) | |
return $RC | |
} | |
function check_selinux() { | |
ENABLED=$(getenforce) | |
if [[ $ENABLED != 'Enforcing' ]]; then | |
RC=0 | |
else | |
RC=1 | |
fi | |
print_status $RC "Is SELinux disabled?" | |
(( OVERALL_RC += $RC )) | |
return $RC | |
} | |
function check() { | |
# Wrapper to invoke both check_commmand and version check in one go | |
if [[ $# -eq 4 ]]; then | |
DISPLAY_NAME=$4 | |
elif [[ $# -eq 2 ]]; then | |
DISPLAY_NAME=$2 | |
else | |
DISPLAY_NAME=$1 | |
fi | |
check_command_exists $1 $DISPLAY_NAME | |
# check_version takes {3,4} arguments | |
if [[ "$?" -eq 0 && "$#" -ge 3 && $DISABLE_VERSION_CHECK -eq 0 ]]; then | |
check_version $* | |
fi | |
} | |
function check_service() { | |
PORT=$1 | |
NAME=$2 | |
echo -e -n "Checking if port $PORT (required by $NAME) is in use: " | |
RC=0 | |
cat /proc/net/{udp*,tcp*} | cut -d: -f3 | cut -d' ' -f1 | grep -q $(printf "%04x" $PORT) && RC=1 | |
print_status $RC | |
(( OVERALL_RC += $RC )) | |
} | |
function check_preexisting_dcos() { | |
echo -e -n 'Checking if DC/OS is already installed: ' | |
if [[ ( -d /etc/systemd/system/dcos.target ) || ( -d /etc/systemd/system/dcos.target.wants ) || ( -d /opt/mesosphere ) ]]; then | |
# this will print: Checking if DC/OS is already installed: FAIL (Currently installed) | |
print_status 1 "${NORMAL}(Currently installed)" | |
echo | |
cat <<EOM | |
Found an existing DC/OS installation. To reinstall DC/OS on this this machine you must | |
first uninstall DC/OS then run dcos_install.sh. To uninstall DC/OS, follow the product | |
documentation provided with DC/OS. | |
EOM | |
echo | |
exit 1 | |
else | |
print_status 0 "${NORMAL}(Not installed)" | |
fi | |
} | |
function check_docker_device_mapper_loopback() { | |
echo -e -n 'Checking Docker is configured with a production storage driver: ' | |
storage_driver="$(docker info | grep 'Storage Driver' | cut -d ':' -f 2 | tr -d '[[:space:]]')" | |
if [ "$storage_driver" != "devicemapper" ]; then | |
print_status 0 "${NORMAL}(${storage_driver})" | |
return | |
fi | |
data_file="$(docker info | grep 'Data file' | cut -d ':' -f 2 | tr -d '[[:space:]]')" | |
if [[ "${data_file}" == /dev/loop* ]]; then | |
print_status 1 "${NORMAL}(${storage_driver}, ${data_file})" | |
echo | |
cat <<EOM | |
Docker is configured to use the devicemapper storage driver with a loopback | |
device behind it. This is highly recommended against by Docker and the | |
community at large for production use[0][1]. See the docker documentation on | |
selecting an alternate storage driver, or use alternate storage than loopback | |
for the devicemapper driver. | |
[0] https://docs.docker.com/engine/userguide/storagedriver/device-mapper-driver/ | |
[1] http://www.projectatomic.io/blog/2015/06/notes-on-fedora-centos-and-docker-storage-drivers/ | |
EOM | |
echo | |
exit 1 | |
else | |
print_status 0 "${NORMAL}(${storage_driver} ${data_file})" | |
fi | |
} | |
function check_all() { | |
# Disable errexit because we want the preflight checks to run all the way | |
# through and not bail in the middle, which will happen as it relies on | |
# error exit codes | |
set +e | |
echo -e "${BOLD}Running preflight checks${NORMAL}" | |
AGENT_ONLY=0 | |
for ROLE in $ROLES; do | |
if [[ $ROLE = "slave" || $ROLE = "slave_public" ]]; then | |
AGENT_ONLY=1 | |
break | |
fi | |
done | |
check_preexisting_dcos | |
check_selinux | |
check_sort_capability | |
local docker_version=$(command -v docker >/dev/null 2>&1 && docker version 2>/dev/null | awk ' | |
BEGIN { | |
version = 0 | |
client_version = 0 | |
server_version = 0 | |
} | |
{ | |
if($1 == "Server:") { | |
server = 1 | |
client = 0 | |
} else if($1 == "Client:") { | |
server = 0 | |
client = 1 | |
} else if ($1 == "Server" && $2 == "version:") { | |
server_version = $3 | |
} else if ($1 == "Client" && $2 == "version:") { | |
client_version = $3 | |
} | |
if(server && $1 == "Version:") { | |
server_version = $2 | |
} else if(client && $1 == "Version:") { | |
client_version = $2 | |
} | |
} | |
END { | |
if(client_version == server_version) { | |
version = client_version | |
} else { | |
cv_length = split(client_version, cv, ".") | |
sv_length = split(server_version, sv, ".") | |
y = cv_length > sv_length ? cv_length : sv_length | |
for(i = 1; i <= y; i++) { | |
if(cv[i] < sv[i]) { | |
version = client_version | |
break | |
} else if(sv[i] < cv[i]) { | |
version = server_version | |
break | |
} | |
} | |
} | |
print version | |
} | |
') | |
# CoreOS stable as of Aug 2015 has 1.6.2 | |
check docker 1.6 "$docker_version" | |
check curl | |
check bash | |
check ping | |
check tar | |
check xz | |
check unzip | |
check ipset | |
check systemd-notify | |
# $ systemctl --version -> | |
# systemd nnn | |
# compiler option string | |
# Pick up just the first line of output and get the version from it | |
check systemctl 200 $(systemctl --version | head -1 | cut -f2 -d' ') systemd | |
echo -e -n "Checking if group 'nogroup' exists: " | |
getent group nogroup > /dev/null | |
RC=$? | |
print_status $RC | |
(( OVERALL_RC += $RC )) | |
# Run service check on master node only | |
if [[ $AGENT_ONLY -eq 0 ]]; then | |
# master node service checks | |
for service in "53 spartan" "80 adminrouter" "443 adminrouter" "1050 3dt" "2181 zookeeper" "5050 mesos-master" "7070 cosmos" "8080 marathon" "8101 dcos-oauth" "8123 mesos-dns" "8181 exhibitor" "9000 metronome" "9942 metronome" "9990 cosmos" "15055 dcos-history" "33107 navstar" "36771 marathon" "41281 zookeeper" "42819 spartan" "43911 minuteman" "46839 metronome" "61053 mesos-dns" "61420 epmd" "61421 minuteman" "62053 spartan" "62080 navstar" | |
do | |
check_service $service | |
done | |
else | |
# agent / public agent node service checks | |
for service in "53 spartan" "5051 mesos-agent" "34451 navstar" "39851 spartan" "43995 minuteman" "61001 agent-adminrouter" "61420 epmd" "61421 minuteman" "62053 spartan" "62080 navstar" | |
do | |
check_service $service | |
done | |
fi | |
# Check we're not in docker on devicemapper loopback as storage driver. | |
check_docker_device_mapper_loopback | |
for role in "$ROLES" | |
do | |
if [ "$role" != "master" -a "$role" != "slave" -a "$role" != "slave_public" -a "$role" != "minuteman" ]; then | |
echo -e "${RED}FAIL Invalid role $role. Role must be one of {master,slave,slave_public}${NORMAL}" | |
(( OVERALL_RC += 1 )) | |
fi | |
done | |
return $OVERALL_RC | |
} | |
function dcos_install() | |
{ | |
# Enable errexit | |
set -e | |
setup_directories | |
setup_dcos_roles | |
configure_dcos | |
setup_and_start_services | |
} | |
function usage() | |
{ | |
echo -e "${BOLD}Usage: $0 [--disable-preflight|--preflight-only] <roles>${NORMAL}" | |
} | |
function main() | |
{ | |
eval set -- "$ARGS" | |
while true ; do | |
case "$1" in | |
-d|--disable-preflight) DISABLE_PREFLIGHT=1; shift ;; | |
-p|--preflight-only) PREFLIGHT_ONLY=1 ; shift ;; | |
--no-block-dcos-setup) SYSTEMCTL_NO_BLOCK=1; shift ;; | |
-h|--help) usage; exit 1 ;; | |
--) shift ; break ;; | |
*) usage ; exit 1 ;; | |
esac | |
done | |
if [[ $DISABLE_PREFLIGHT -eq 1 && $PREFLIGHT_ONLY -eq 1 ]]; then | |
echo -e 'Both --disable-preflight and --preflight-only can not be specified' | |
usage | |
exit 1 | |
fi | |
shift $(($OPTIND - 1)) | |
ROLES=$@ | |
if [[ $PREFLIGHT_ONLY -eq 1 ]] ; then | |
check_all | |
else | |
if [[ -z $ROLES ]] ; then | |
echo -e 'Atleast one role name must be specified' | |
usage | |
exit 1 | |
fi | |
echo -e "${BOLD}Starting DC/OS Install Process${NORMAL}" | |
if [[ $DISABLE_PREFLIGHT -eq 0 ]] ; then | |
check_all | |
RC=$? | |
if [[ $RC -ne 0 ]]; then | |
echo 'Preflight checks failed. Exiting installation. Please consult product documentation' | |
exit $RC | |
fi | |
fi | |
# Run actual install | |
dcos_install | |
fi | |
} | |
# Run it all | |
main |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment