2014-09-09 10:17:32 +00:00
|
|
|
#!/bin/bash
|
|
|
|
|
2015-05-01 16:19:44 +00:00
|
|
|
# Copyright 2014 The Kubernetes Authors All rights reserved.
|
2014-09-09 10:17:32 +00:00
|
|
|
#
|
|
|
|
# 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.
|
|
|
|
|
|
|
|
# A library of helper functions and constant for the local config.
|
|
|
|
|
2015-11-03 16:01:41 +00:00
|
|
|
# Experimental flags can be removed/renamed at any time.
|
|
|
|
# The intent is to allow experimentation/advanced functionality before we
|
|
|
|
# are ready to commit to supporting it.
|
|
|
|
# Experimental functionality:
|
|
|
|
# KUBE_SHARE_MASTER=true
|
2015-11-03 18:12:17 +00:00
|
|
|
# Detect and reuse an existing master; useful if you want to
|
2015-11-03 16:01:41 +00:00
|
|
|
# create more nodes, perhaps with a different instance type or in
|
|
|
|
# a different subnet/AZ
|
|
|
|
# KUBE_SUBNET_CIDR=172.20.1.0/24
|
|
|
|
# Override the default subnet CIDR; useful if you want to create
|
|
|
|
# a second subnet. The default subnet is 172.20.0.0/24. The VPC
|
|
|
|
# is created with 172.20.0.0/16; you must pick a sub-CIDR of that.
|
|
|
|
|
2014-09-09 10:17:32 +00:00
|
|
|
# Use the config file specified in $KUBE_CONFIG_FILE, or default to
|
|
|
|
# config-default.sh.
|
2015-02-11 17:50:47 +00:00
|
|
|
KUBE_ROOT=$(dirname "${BASH_SOURCE}")/../..
|
|
|
|
source "${KUBE_ROOT}/cluster/aws/${KUBE_CONFIG_FILE-"config-default.sh"}"
|
2015-04-10 00:07:24 +00:00
|
|
|
source "${KUBE_ROOT}/cluster/common.sh"
|
2014-09-09 10:17:32 +00:00
|
|
|
|
2015-06-12 16:33:17 +00:00
|
|
|
ALLOCATE_NODE_CIDRS=true
|
|
|
|
|
2015-06-13 04:34:43 +00:00
|
|
|
NODE_INSTANCE_PREFIX="${INSTANCE_PREFIX}-minion"
|
2015-11-03 16:01:41 +00:00
|
|
|
|
2015-11-03 18:12:17 +00:00
|
|
|
# The Auto Scaling Group (ASG) name must be unique, so we include the zone
|
2015-11-03 16:01:41 +00:00
|
|
|
ASG_NAME="${NODE_INSTANCE_PREFIX}-group-${ZONE}"
|
2015-06-13 04:34:43 +00:00
|
|
|
|
2015-06-25 20:00:04 +00:00
|
|
|
# We could allow the master disk volume id to be specified in future
|
|
|
|
MASTER_DISK_ID=
|
|
|
|
|
2015-06-25 03:13:17 +00:00
|
|
|
# Defaults: ubuntu -> vivid
|
|
|
|
if [[ "${KUBE_OS_DISTRIBUTION}" == "ubuntu" ]]; then
|
|
|
|
KUBE_OS_DISTRIBUTION=vivid
|
|
|
|
fi
|
|
|
|
|
2015-05-13 20:39:22 +00:00
|
|
|
case "${KUBE_OS_DISTRIBUTION}" in
|
2015-06-25 03:13:17 +00:00
|
|
|
trusty|wheezy|jessie|vivid|coreos)
|
2015-05-13 20:39:22 +00:00
|
|
|
source "${KUBE_ROOT}/cluster/aws/${KUBE_OS_DISTRIBUTION}/util.sh"
|
|
|
|
;;
|
|
|
|
*)
|
|
|
|
echo "Cannot start cluster using os distro: ${KUBE_OS_DISTRIBUTION}" >&2
|
|
|
|
exit 2
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
|
2015-03-26 19:47:49 +00:00
|
|
|
# This removes the final character in bash (somehow)
|
2015-03-27 15:53:17 +00:00
|
|
|
AWS_REGION=${ZONE%?}
|
2015-03-26 19:47:49 +00:00
|
|
|
|
|
|
|
export AWS_DEFAULT_REGION=${AWS_REGION}
|
2015-11-11 04:30:42 +00:00
|
|
|
export AWS_DEFAULT_OUTPUT=text
|
|
|
|
AWS_CMD="aws ec2"
|
|
|
|
AWS_ASG_CMD="aws autoscaling"
|
2014-09-09 10:17:32 +00:00
|
|
|
|
2015-11-03 16:01:41 +00:00
|
|
|
VPC_CIDR_BASE=172.20
|
2015-04-23 09:01:17 +00:00
|
|
|
MASTER_IP_SUFFIX=.9
|
2015-11-03 16:01:41 +00:00
|
|
|
MASTER_INTERNAL_IP=${VPC_CIDR_BASE}.0${MASTER_IP_SUFFIX}
|
|
|
|
VPC_CIDR=${VPC_CIDR_BASE}.0.0/16
|
|
|
|
SUBNET_CIDR=${VPC_CIDR_BASE}.0.0/24
|
|
|
|
if [[ -n "${KUBE_SUBNET_CIDR:-}" ]]; then
|
|
|
|
echo "Using subnet CIDR override: ${KUBE_SUBNET_CIDR}"
|
|
|
|
SUBNET_CIDR=${KUBE_SUBNET_CIDR}
|
|
|
|
fi
|
2015-03-03 17:18:12 +00:00
|
|
|
|
2015-06-05 02:03:50 +00:00
|
|
|
MASTER_SG_NAME="kubernetes-master-${CLUSTER_ID}"
|
2015-11-24 03:05:33 +00:00
|
|
|
NODE_SG_NAME="kubernetes-minion-${CLUSTER_ID}"
|
2015-06-05 02:03:50 +00:00
|
|
|
|
2015-06-06 20:35:12 +00:00
|
|
|
# Be sure to map all the ephemeral drives. We can specify more than we actually have.
|
|
|
|
# TODO: Actually mount the correct number (especially if we have more), though this is non-trivial, and
|
|
|
|
# only affects the big storage instance types, which aren't a typical use case right now.
|
2015-08-18 18:03:23 +00:00
|
|
|
BLOCK_DEVICE_MAPPINGS_BASE="{\"DeviceName\": \"/dev/sdc\",\"VirtualName\":\"ephemeral0\"},{\"DeviceName\": \"/dev/sdd\",\"VirtualName\":\"ephemeral1\"},{\"DeviceName\": \"/dev/sde\",\"VirtualName\":\"ephemeral2\"},{\"DeviceName\": \"/dev/sdf\",\"VirtualName\":\"ephemeral3\"}"
|
|
|
|
MASTER_BLOCK_DEVICE_MAPPINGS="[{\"DeviceName\":\"/dev/sda1\",\"Ebs\":{\"DeleteOnTermination\":true,\"VolumeSize\":${MASTER_ROOT_DISK_SIZE},\"VolumeType\":\"${MASTER_ROOT_DISK_TYPE}\"}}, ${BLOCK_DEVICE_MAPPINGS_BASE}]"
|
2015-11-24 03:05:07 +00:00
|
|
|
NODE_BLOCK_DEVICE_MAPPINGS="[{\"DeviceName\":\"/dev/sda1\",\"Ebs\":{\"DeleteOnTermination\":true,\"VolumeSize\":${NODE_ROOT_DISK_SIZE},\"VolumeType\":\"${NODE_ROOT_DISK_TYPE}\"}}, ${BLOCK_DEVICE_MAPPINGS_BASE}]"
|
2015-06-06 20:35:12 +00:00
|
|
|
|
2014-11-06 22:27:15 +00:00
|
|
|
# TODO (bburns) Parameterize this for multiple cluster per project
|
2014-09-09 10:17:32 +00:00
|
|
|
|
|
|
|
function get_vpc_id {
|
2015-11-11 04:30:42 +00:00
|
|
|
$AWS_CMD describe-vpcs \
|
2015-03-25 13:23:22 +00:00
|
|
|
--filters Name=tag:Name,Values=kubernetes-vpc \
|
|
|
|
Name=tag:KubernetesCluster,Values=${CLUSTER_ID} \
|
|
|
|
--query Vpcs[].VpcId
|
2014-09-09 10:17:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function get_subnet_id {
|
2015-11-03 15:08:46 +00:00
|
|
|
local vpc_id=$1
|
|
|
|
local az=$2
|
2015-11-11 04:30:42 +00:00
|
|
|
$AWS_CMD describe-subnets \
|
2015-11-03 15:08:46 +00:00
|
|
|
--filters Name=tag:KubernetesCluster,Values=${CLUSTER_ID} \
|
|
|
|
Name=availabilityZone,Values=${az} \
|
|
|
|
Name=vpc-id,Values=${vpc_id} \
|
|
|
|
--query Subnets[].SubnetId
|
2015-04-23 09:01:17 +00:00
|
|
|
}
|
|
|
|
|
2014-09-09 10:17:32 +00:00
|
|
|
function get_igw_id {
|
2015-11-03 15:08:46 +00:00
|
|
|
local vpc_id=$1
|
2015-11-11 04:30:42 +00:00
|
|
|
$AWS_CMD describe-internet-gateways \
|
2015-11-03 15:08:46 +00:00
|
|
|
--filters Name=attachment.vpc-id,Values=${vpc_id} \
|
|
|
|
--query InternetGateways[].InternetGatewayId
|
2014-09-09 10:17:32 +00:00
|
|
|
}
|
|
|
|
|
2015-03-25 12:36:47 +00:00
|
|
|
function get_elbs_in_vpc {
|
2015-11-11 04:30:42 +00:00
|
|
|
# ELB doesn't seem to be on the same platform as the rest of AWS; doesn't support filtering
|
|
|
|
aws elb --output json describe-load-balancers | \
|
2015-03-25 12:36:47 +00:00
|
|
|
python -c "import json,sys; lst = [str(lb['LoadBalancerName']) for lb in json.load(sys.stdin)['LoadBalancerDescriptions'] if lb['VPCId'] == '$1']; print '\n'.join(lst)"
|
|
|
|
}
|
|
|
|
|
2015-06-13 04:34:43 +00:00
|
|
|
function get_instanceid_from_name {
|
2015-03-03 17:21:44 +00:00
|
|
|
local tagName=$1
|
2015-11-11 04:30:42 +00:00
|
|
|
$AWS_CMD describe-instances \
|
2015-03-25 13:23:22 +00:00
|
|
|
--filters Name=tag:Name,Values=${tagName} \
|
|
|
|
Name=instance-state-name,Values=running \
|
|
|
|
Name=tag:KubernetesCluster,Values=${CLUSTER_ID} \
|
2015-06-13 04:34:43 +00:00
|
|
|
--query Reservations[].Instances[].InstanceId
|
2014-09-09 10:17:32 +00:00
|
|
|
}
|
|
|
|
|
2015-06-13 04:34:43 +00:00
|
|
|
function get_instance_public_ip {
|
|
|
|
local instance_id=$1
|
2015-11-11 04:30:42 +00:00
|
|
|
$AWS_CMD describe-instances \
|
2015-06-13 04:34:43 +00:00
|
|
|
--instance-ids ${instance_id} \
|
|
|
|
--query Reservations[].Instances[].NetworkInterfaces[0].Association.PublicIp
|
2015-05-07 22:09:47 +00:00
|
|
|
}
|
2015-03-03 17:21:44 +00:00
|
|
|
|
2015-07-14 17:43:48 +00:00
|
|
|
function get_instance_private_ip {
|
|
|
|
local instance_id=$1
|
2015-11-11 04:30:42 +00:00
|
|
|
$AWS_CMD describe-instances \
|
2015-07-14 17:43:48 +00:00
|
|
|
--instance-ids ${instance_id} \
|
|
|
|
--query Reservations[].Instances[].NetworkInterfaces[0].PrivateIpAddress
|
|
|
|
}
|
|
|
|
|
2015-06-05 02:03:50 +00:00
|
|
|
# Gets a security group id, by name ($1)
|
|
|
|
function get_security_group_id {
|
|
|
|
local name=$1
|
2015-11-11 04:30:42 +00:00
|
|
|
$AWS_CMD describe-security-groups \
|
2015-06-05 02:03:50 +00:00
|
|
|
--filters Name=vpc-id,Values=${VPC_ID} \
|
|
|
|
Name=group-name,Values=${name} \
|
|
|
|
Name=tag:KubernetesCluster,Values=${CLUSTER_ID} \
|
|
|
|
--query SecurityGroups[].GroupId \
|
|
|
|
| tr "\t" "\n"
|
|
|
|
}
|
|
|
|
|
2014-09-09 10:17:32 +00:00
|
|
|
function detect-master () {
|
|
|
|
KUBE_MASTER=${MASTER_NAME}
|
2015-06-13 04:34:43 +00:00
|
|
|
if [[ -z "${KUBE_MASTER_ID-}" ]]; then
|
|
|
|
KUBE_MASTER_ID=$(get_instanceid_from_name ${MASTER_NAME})
|
|
|
|
fi
|
|
|
|
if [[ -z "${KUBE_MASTER_ID-}" ]]; then
|
|
|
|
echo "Could not detect Kubernetes master node. Make sure you've launched a cluster with 'kube-up.sh'"
|
|
|
|
exit 1
|
|
|
|
fi
|
2014-11-06 22:27:15 +00:00
|
|
|
if [[ -z "${KUBE_MASTER_IP-}" ]]; then
|
2015-06-13 04:34:43 +00:00
|
|
|
KUBE_MASTER_IP=$(get_instance_public_ip ${KUBE_MASTER_ID})
|
2014-09-09 10:17:32 +00:00
|
|
|
fi
|
2014-11-06 22:27:15 +00:00
|
|
|
if [[ -z "${KUBE_MASTER_IP-}" ]]; then
|
2015-06-13 04:34:43 +00:00
|
|
|
echo "Could not detect Kubernetes master node IP. Make sure you've launched a cluster with 'kube-up.sh'"
|
2014-09-09 10:17:32 +00:00
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
echo "Using master: $KUBE_MASTER (external IP: $KUBE_MASTER_IP)"
|
|
|
|
}
|
|
|
|
|
2015-06-13 04:34:43 +00:00
|
|
|
|
|
|
|
function query-running-minions () {
|
|
|
|
local query=$1
|
2015-11-11 04:30:42 +00:00
|
|
|
$AWS_CMD describe-instances \
|
2015-06-13 04:34:43 +00:00
|
|
|
--filters Name=instance-state-name,Values=running \
|
|
|
|
Name=vpc-id,Values=${VPC_ID} \
|
|
|
|
Name=tag:KubernetesCluster,Values=${CLUSTER_ID} \
|
2015-11-03 16:16:18 +00:00
|
|
|
Name=tag:aws:autoscaling:groupName,Values=${ASG_NAME} \
|
2015-11-24 03:06:00 +00:00
|
|
|
Name=tag:Role,Values=${NODE_TAG} \
|
2015-06-13 04:34:43 +00:00
|
|
|
--query ${query}
|
|
|
|
}
|
|
|
|
|
|
|
|
function find-running-minions () {
|
2015-11-24 03:02:38 +00:00
|
|
|
NODE_IDS=()
|
2015-11-24 03:04:40 +00:00
|
|
|
NODE_NAMES=()
|
2015-06-13 04:34:43 +00:00
|
|
|
for id in $(query-running-minions "Reservations[].Instances[].InstanceId"); do
|
2015-11-24 03:02:38 +00:00
|
|
|
NODE_IDS+=("${id}")
|
2015-06-13 04:34:43 +00:00
|
|
|
|
|
|
|
# We use the minion ids as the name
|
2015-11-24 03:04:40 +00:00
|
|
|
NODE_NAMES+=("${id}")
|
2015-06-13 04:34:43 +00:00
|
|
|
done
|
|
|
|
}
|
|
|
|
|
2015-11-09 07:33:06 +00:00
|
|
|
function detect-nodes () {
|
2015-06-13 04:34:43 +00:00
|
|
|
find-running-minions
|
|
|
|
|
2015-11-24 03:04:40 +00:00
|
|
|
# This is inefficient, but we want NODE_NAMES / NODE_IDS to be ordered the same as KUBE_NODE_IP_ADDRESSES
|
2015-11-24 03:00:46 +00:00
|
|
|
KUBE_NODE_IP_ADDRESSES=()
|
2015-11-24 03:04:40 +00:00
|
|
|
for (( i=0; i<${#NODE_NAMES[@]}; i++)); do
|
2015-05-07 22:09:47 +00:00
|
|
|
local minion_ip
|
2015-11-24 03:01:03 +00:00
|
|
|
if [[ "${ENABLE_NODE_PUBLIC_IP}" == "true" ]]; then
|
2015-11-24 03:04:40 +00:00
|
|
|
minion_ip=$(get_instance_public_ip ${NODE_NAMES[$i]})
|
2015-05-07 22:09:47 +00:00
|
|
|
else
|
2015-11-24 03:04:40 +00:00
|
|
|
minion_ip=$(get_instance_private_ip ${NODE_NAMES[$i]})
|
2015-05-07 22:09:47 +00:00
|
|
|
fi
|
2015-11-24 03:04:40 +00:00
|
|
|
echo "Found minion ${i}: ${NODE_NAMES[$i]} @ ${minion_ip}"
|
2015-11-24 03:00:46 +00:00
|
|
|
KUBE_NODE_IP_ADDRESSES+=("${minion_ip}")
|
2014-09-09 10:17:32 +00:00
|
|
|
done
|
2015-06-13 04:34:43 +00:00
|
|
|
|
2015-11-24 03:00:46 +00:00
|
|
|
if [[ -z "$KUBE_NODE_IP_ADDRESSES" ]]; then
|
2014-09-09 10:17:32 +00:00
|
|
|
echo "Could not detect Kubernetes minion nodes. Make sure you've launched a cluster with 'kube-up.sh'"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2015-06-05 02:03:50 +00:00
|
|
|
function detect-security-groups {
|
|
|
|
if [[ -z "${MASTER_SG_ID-}" ]]; then
|
|
|
|
MASTER_SG_ID=$(get_security_group_id "${MASTER_SG_NAME}")
|
|
|
|
if [[ -z "${MASTER_SG_ID}" ]]; then
|
|
|
|
echo "Could not detect Kubernetes master security group. Make sure you've launched a cluster with 'kube-up.sh'"
|
|
|
|
exit 1
|
|
|
|
else
|
|
|
|
echo "Using master security group: ${MASTER_SG_NAME} ${MASTER_SG_ID}"
|
|
|
|
fi
|
|
|
|
fi
|
2015-11-24 03:05:33 +00:00
|
|
|
if [[ -z "${NODE_SG_ID-}" ]]; then
|
|
|
|
NODE_SG_ID=$(get_security_group_id "${NODE_SG_NAME}")
|
|
|
|
if [[ -z "${NODE_SG_ID}" ]]; then
|
2015-06-05 02:03:50 +00:00
|
|
|
echo "Could not detect Kubernetes minion security group. Make sure you've launched a cluster with 'kube-up.sh'"
|
|
|
|
exit 1
|
|
|
|
else
|
2015-11-24 03:05:33 +00:00
|
|
|
echo "Using minion security group: ${NODE_SG_NAME} ${NODE_SG_ID}"
|
2015-06-05 02:03:50 +00:00
|
|
|
fi
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2015-03-12 13:35:36 +00:00
|
|
|
# Detects the AMI to use (considering the region)
|
2015-06-06 17:19:37 +00:00
|
|
|
# This really should be in the various distro-specific util functions,
|
|
|
|
# but CoreOS uses this for the master, so for now it is here.
|
|
|
|
#
|
|
|
|
# TODO: Remove this and just have each distro implement detect-image
|
2015-03-12 13:35:36 +00:00
|
|
|
#
|
|
|
|
# Vars set:
|
|
|
|
# AWS_IMAGE
|
|
|
|
function detect-image () {
|
2015-06-06 17:19:37 +00:00
|
|
|
case "${KUBE_OS_DISTRIBUTION}" in
|
2015-06-25 03:13:17 +00:00
|
|
|
trusty|coreos)
|
|
|
|
detect-trusty-image
|
2015-06-06 17:19:37 +00:00
|
|
|
;;
|
2015-06-16 22:23:25 +00:00
|
|
|
vivid)
|
|
|
|
detect-vivid-image
|
2015-06-06 17:19:37 +00:00
|
|
|
;;
|
|
|
|
wheezy)
|
|
|
|
detect-wheezy-image
|
|
|
|
;;
|
2015-06-06 17:19:37 +00:00
|
|
|
jessie)
|
|
|
|
detect-jessie-image
|
|
|
|
;;
|
2015-06-06 17:19:37 +00:00
|
|
|
*)
|
2015-10-05 13:21:52 +00:00
|
|
|
echo "Please specify AWS_IMAGE directly (distro ${KUBE_OS_DISTRIBUTION} not recognized)"
|
2015-06-06 17:19:37 +00:00
|
|
|
exit 2
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
2015-06-25 03:13:17 +00:00
|
|
|
# Detects the AMI to use for trusty (considering the region)
|
2015-06-06 17:19:37 +00:00
|
|
|
# Used by CoreOS & Ubuntu
|
|
|
|
#
|
|
|
|
# Vars set:
|
|
|
|
# AWS_IMAGE
|
2015-06-25 03:13:17 +00:00
|
|
|
function detect-trusty-image () {
|
2015-03-12 13:35:36 +00:00
|
|
|
# This is the ubuntu 14.04 image for <region>, amd64, hvm:ebs-ssd
|
|
|
|
# See here: http://cloud-images.ubuntu.com/locator/ec2/ for other images
|
|
|
|
# This will need to be updated from time to time as amis are deprecated
|
|
|
|
if [[ -z "${AWS_IMAGE-}" ]]; then
|
2015-03-26 19:47:49 +00:00
|
|
|
case "${AWS_REGION}" in
|
2015-03-12 13:35:36 +00:00
|
|
|
ap-northeast-1)
|
|
|
|
AWS_IMAGE=ami-93876e93
|
|
|
|
;;
|
|
|
|
|
|
|
|
ap-southeast-1)
|
|
|
|
AWS_IMAGE=ami-66546234
|
|
|
|
;;
|
|
|
|
|
|
|
|
eu-central-1)
|
|
|
|
AWS_IMAGE=ami-e2a694ff
|
|
|
|
;;
|
|
|
|
|
|
|
|
eu-west-1)
|
|
|
|
AWS_IMAGE=ami-d7fd6ea0
|
|
|
|
;;
|
|
|
|
|
|
|
|
sa-east-1)
|
|
|
|
AWS_IMAGE=ami-a357eebe
|
|
|
|
;;
|
|
|
|
|
|
|
|
us-east-1)
|
|
|
|
AWS_IMAGE=ami-6089d208
|
|
|
|
;;
|
|
|
|
|
|
|
|
us-west-1)
|
|
|
|
AWS_IMAGE=ami-cf7d998b
|
|
|
|
;;
|
|
|
|
|
|
|
|
cn-north-1)
|
|
|
|
AWS_IMAGE=ami-d436a4ed
|
|
|
|
;;
|
|
|
|
|
|
|
|
us-gov-west-1)
|
|
|
|
AWS_IMAGE=ami-01523322
|
|
|
|
;;
|
|
|
|
|
|
|
|
ap-southeast-2)
|
|
|
|
AWS_IMAGE=ami-cd4e3ff7
|
|
|
|
;;
|
|
|
|
|
|
|
|
us-west-2)
|
|
|
|
AWS_IMAGE=ami-3b14370b
|
|
|
|
;;
|
|
|
|
|
|
|
|
*)
|
2015-10-05 13:05:17 +00:00
|
|
|
echo "Please specify AWS_IMAGE directly (region ${AWS_REGION} not recognized)"
|
2015-03-12 13:35:36 +00:00
|
|
|
exit 1
|
|
|
|
esac
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2015-06-04 18:16:23 +00:00
|
|
|
# Computes the AWS fingerprint for a public key file ($1)
|
|
|
|
# $1: path to public key file
|
|
|
|
# Note that this is a different hash from the OpenSSH hash.
|
|
|
|
# But AWS gives us this public key hash in the describe keys output, so we should stick with this format.
|
|
|
|
# Hopefully this will be done by the aws cli tool one day: https://github.com/aws/aws-cli/issues/191
|
2015-07-01 11:10:48 +00:00
|
|
|
# NOTE: This does not work on Mavericks, due to an odd ssh-keygen version, so we use get-ssh-fingerprint instead
|
2015-06-04 18:16:23 +00:00
|
|
|
function get-aws-fingerprint {
|
|
|
|
local -r pubkey_path=$1
|
2015-06-12 20:29:37 +00:00
|
|
|
ssh-keygen -f ${pubkey_path} -e -m PKCS8 | openssl rsa -pubin -outform DER | openssl md5 -c | sed -e 's/(stdin)= //g'
|
2015-06-04 18:16:23 +00:00
|
|
|
}
|
|
|
|
|
2015-07-01 11:10:48 +00:00
|
|
|
# Computes the SSH fingerprint for a public key file ($1)
|
|
|
|
# #1: path to public key file
|
|
|
|
# Note this is different from the AWS fingerprint; see notes on get-aws-fingerprint
|
|
|
|
function get-ssh-fingerprint {
|
|
|
|
local -r pubkey_path=$1
|
|
|
|
ssh-keygen -lf ${pubkey_path} | cut -f2 -d' '
|
|
|
|
}
|
|
|
|
|
2015-06-04 18:16:23 +00:00
|
|
|
# Import an SSH public key to AWS.
|
|
|
|
# Ignores duplicate names; recommended to use a name that includes the public key hash.
|
|
|
|
# $1 name
|
|
|
|
# $2 public key path
|
|
|
|
function import-public-key {
|
|
|
|
local -r name=$1
|
|
|
|
local -r path=$2
|
|
|
|
|
|
|
|
local ok=1
|
|
|
|
local output=""
|
|
|
|
output=$($AWS_CMD import-key-pair --key-name ${name} --public-key-material "file://${path}" 2>&1) || ok=0
|
|
|
|
if [[ ${ok} == 0 ]]; then
|
|
|
|
# Idempotency: ignore if duplicate name
|
|
|
|
if [[ "${output}" != *"InvalidKeyPair.Duplicate"* ]]; then
|
|
|
|
echo "Error importing public key"
|
|
|
|
echo "Output: ${output}"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2015-06-05 02:03:50 +00:00
|
|
|
# Robustly try to create a security group, if it does not exist.
|
|
|
|
# $1: The name of security group; will be created if not exists
|
|
|
|
# $2: Description for security group (used if created)
|
|
|
|
#
|
|
|
|
# Note that this doesn't actually return the sgid; we need to re-query
|
|
|
|
function create-security-group {
|
|
|
|
local -r name=$1
|
|
|
|
local -r description=$2
|
|
|
|
|
|
|
|
local sgid=$(get_security_group_id "${name}")
|
|
|
|
if [[ -z "$sgid" ]]; then
|
|
|
|
echo "Creating security group ${name}."
|
2015-11-11 04:30:42 +00:00
|
|
|
sgid=$($AWS_CMD create-security-group --group-name "${name}" --description "${description}" --vpc-id "${VPC_ID}" --query GroupId)
|
2015-06-05 02:03:50 +00:00
|
|
|
add-tag $sgid KubernetesCluster ${CLUSTER_ID}
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
# Authorize ingress to a security group.
|
|
|
|
# Attempts to be idempotent, though we end up checking the output looking for error-strings.
|
|
|
|
# $1 group-id
|
|
|
|
# $2.. arguments to pass to authorize-security-group-ingress
|
|
|
|
function authorize-security-group-ingress {
|
|
|
|
local -r sgid=$1
|
|
|
|
shift
|
|
|
|
local ok=1
|
|
|
|
local output=""
|
|
|
|
output=$($AWS_CMD authorize-security-group-ingress --group-id "${sgid}" $@ 2>&1) || ok=0
|
|
|
|
if [[ ${ok} == 0 ]]; then
|
|
|
|
# Idempotency: ignore if duplicate rule
|
|
|
|
if [[ "${output}" != *"InvalidPermission.Duplicate"* ]]; then
|
|
|
|
echo "Error creating security group ingress rule"
|
|
|
|
echo "Output: ${output}"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2015-06-25 20:00:04 +00:00
|
|
|
# Gets master persistent volume, if exists
|
|
|
|
# Sets MASTER_DISK_ID
|
|
|
|
function find-master-pd {
|
|
|
|
local name=${MASTER_NAME}-pd
|
|
|
|
if [[ -z "${MASTER_DISK_ID}" ]]; then
|
2015-11-11 04:30:42 +00:00
|
|
|
MASTER_DISK_ID=`$AWS_CMD describe-volumes \
|
2015-06-25 20:00:04 +00:00
|
|
|
--filters Name=availability-zone,Values=${ZONE} \
|
|
|
|
Name=tag:Name,Values=${name} \
|
|
|
|
Name=tag:KubernetesCluster,Values=${CLUSTER_ID} \
|
|
|
|
--query Volumes[].VolumeId`
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
# Gets or creates master persistent volume
|
|
|
|
# Sets MASTER_DISK_ID
|
|
|
|
function ensure-master-pd {
|
|
|
|
local name=${MASTER_NAME}-pd
|
|
|
|
|
|
|
|
find-master-pd
|
|
|
|
|
|
|
|
if [[ -z "${MASTER_DISK_ID}" ]]; then
|
|
|
|
echo "Creating master disk: size ${MASTER_DISK_SIZE}GB, type ${MASTER_DISK_TYPE}"
|
2015-11-11 04:30:42 +00:00
|
|
|
MASTER_DISK_ID=`$AWS_CMD create-volume --availability-zone ${ZONE} --volume-type ${MASTER_DISK_TYPE} --size ${MASTER_DISK_SIZE} --query VolumeId`
|
2015-06-25 20:00:04 +00:00
|
|
|
add-tag ${MASTER_DISK_ID} Name ${name}
|
|
|
|
add-tag ${MASTER_DISK_ID} KubernetesCluster ${CLUSTER_ID}
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2015-05-14 16:55:31 +00:00
|
|
|
# Creates a new DHCP option set configured correctly for Kubernetes
|
|
|
|
# Sets DHCP_OPTION_SET_ID
|
|
|
|
function create-dhcp-option-set () {
|
|
|
|
case "${AWS_REGION}" in
|
|
|
|
us-east-1)
|
|
|
|
OPTION_SET_DOMAIN=ec2.internal
|
|
|
|
;;
|
|
|
|
|
|
|
|
*)
|
|
|
|
OPTION_SET_DOMAIN="${AWS_REGION}.compute.internal"
|
|
|
|
esac
|
|
|
|
|
2015-11-11 04:30:42 +00:00
|
|
|
DHCP_OPTION_SET_ID=$($AWS_CMD create-dhcp-options --dhcp-configuration Key=domain-name,Values=${OPTION_SET_DOMAIN} Key=domain-name-servers,Values=AmazonProvidedDNS --query DhcpOptions.DhcpOptionsId)
|
2015-05-14 16:55:31 +00:00
|
|
|
|
|
|
|
add-tag ${DHCP_OPTION_SET_ID} Name kubernetes-dhcp-option-set
|
|
|
|
add-tag ${DHCP_OPTION_SET_ID} KubernetesCluster ${CLUSTER_ID}
|
|
|
|
|
2015-11-11 04:30:42 +00:00
|
|
|
$AWS_CMD associate-dhcp-options --dhcp-options-id ${DHCP_OPTION_SET_ID} --vpc-id ${VPC_ID} > $LOG
|
2015-05-14 16:55:31 +00:00
|
|
|
|
|
|
|
echo "Using DHCP option set ${DHCP_OPTION_SET_ID}"
|
|
|
|
}
|
|
|
|
|
2014-11-06 22:27:15 +00:00
|
|
|
# Verify prereqs
|
|
|
|
function verify-prereqs {
|
2015-10-21 03:58:24 +00:00
|
|
|
build-runtime-config
|
2015-10-06 18:55:04 +00:00
|
|
|
|
2015-03-25 19:36:20 +00:00
|
|
|
if [[ "$(which aws)" == "" ]]; then
|
2014-11-06 22:27:15 +00:00
|
|
|
echo "Can't find aws in PATH, please fix and retry."
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Create a temp dir that'll be deleted at the end of this bash session.
|
|
|
|
#
|
|
|
|
# Vars set:
|
|
|
|
# KUBE_TEMP
|
|
|
|
function ensure-temp-dir {
|
|
|
|
if [[ -z ${KUBE_TEMP-} ]]; then
|
|
|
|
KUBE_TEMP=$(mktemp -d -t kubernetes.XXXXXX)
|
|
|
|
trap 'rm -rf "${KUBE_TEMP}"' EXIT
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
# Take the local tar files and upload them to S3. They will then be
|
|
|
|
# downloaded by the master as part of the start up script for the master.
|
|
|
|
#
|
|
|
|
# Assumed vars:
|
|
|
|
# SERVER_BINARY_TAR
|
|
|
|
# SALT_TAR
|
|
|
|
# Vars set:
|
|
|
|
# SERVER_BINARY_TAR_URL
|
|
|
|
# SALT_TAR_URL
|
|
|
|
function upload-server-tars() {
|
|
|
|
SERVER_BINARY_TAR_URL=
|
|
|
|
SALT_TAR_URL=
|
|
|
|
|
2015-06-09 15:05:25 +00:00
|
|
|
ensure-temp-dir
|
|
|
|
|
2015-03-12 14:55:43 +00:00
|
|
|
if [[ -z ${AWS_S3_BUCKET-} ]]; then
|
|
|
|
local project_hash=
|
|
|
|
local key=$(aws configure get aws_access_key_id)
|
|
|
|
if which md5 > /dev/null 2>&1; then
|
|
|
|
project_hash=$(md5 -q -s "${USER} ${key}")
|
|
|
|
else
|
|
|
|
project_hash=$(echo -n "${USER} ${key}" | md5sum | awk '{ print $1 }')
|
|
|
|
fi
|
|
|
|
AWS_S3_BUCKET="kubernetes-staging-${project_hash}"
|
2014-11-06 22:27:15 +00:00
|
|
|
fi
|
|
|
|
|
|
|
|
echo "Uploading to Amazon S3"
|
2015-08-01 18:06:13 +00:00
|
|
|
|
|
|
|
if ! aws s3api get-bucket-location --bucket ${AWS_S3_BUCKET} > /dev/null 2>&1 ; then
|
2015-03-12 14:55:43 +00:00
|
|
|
echo "Creating ${AWS_S3_BUCKET}"
|
2015-03-12 14:36:24 +00:00
|
|
|
|
|
|
|
# Buckets must be globally uniquely named, so always create in a known region
|
|
|
|
# We default to us-east-1 because that's the canonical region for S3,
|
|
|
|
# and then the bucket is most-simply named (s3.amazonaws.com)
|
|
|
|
aws s3 mb "s3://${AWS_S3_BUCKET}" --region ${AWS_S3_REGION}
|
2015-05-22 05:12:36 +00:00
|
|
|
|
2015-10-05 13:11:03 +00:00
|
|
|
echo "Confirming bucket was created..."
|
|
|
|
|
2015-05-22 05:12:36 +00:00
|
|
|
local attempt=0
|
|
|
|
while true; do
|
2015-08-01 18:06:13 +00:00
|
|
|
if ! aws s3 ls --region ${AWS_S3_REGION} "s3://${AWS_S3_BUCKET}" > /dev/null 2>&1; then
|
2015-10-05 13:11:03 +00:00
|
|
|
if (( attempt > 120 )); then
|
2015-05-22 05:12:36 +00:00
|
|
|
echo
|
2015-05-23 07:12:24 +00:00
|
|
|
echo -e "${color_red}Unable to confirm bucket creation." >&2
|
2015-05-22 05:12:36 +00:00
|
|
|
echo "Please ensure that s3://${AWS_S3_BUCKET} exists" >&2
|
2015-05-23 07:12:24 +00:00
|
|
|
echo -e "and run the script again. (sorry!)${color_norm}" >&2
|
2015-05-22 05:12:36 +00:00
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
else
|
|
|
|
break
|
|
|
|
fi
|
|
|
|
attempt=$(($attempt+1))
|
|
|
|
sleep 1
|
|
|
|
done
|
2015-03-12 14:36:24 +00:00
|
|
|
fi
|
|
|
|
|
2015-11-11 04:30:42 +00:00
|
|
|
local s3_bucket_location=$(aws s3api get-bucket-location --bucket ${AWS_S3_BUCKET})
|
2015-03-27 19:57:34 +00:00
|
|
|
local s3_url_base=https://s3-${s3_bucket_location}.amazonaws.com
|
2015-03-31 12:41:12 +00:00
|
|
|
if [[ "${s3_bucket_location}" == "None" ]]; then
|
|
|
|
# "US Classic" does not follow the pattern
|
2015-03-12 14:36:24 +00:00
|
|
|
s3_url_base=https://s3.amazonaws.com
|
2015-08-01 18:06:13 +00:00
|
|
|
s3_bucket_location=us-east-1
|
2015-11-26 03:37:28 +00:00
|
|
|
elif [[ "${s3_bucket_location}" == "cn-north-1" ]]; then
|
|
|
|
s3_url_base=https://s3.cn-north-1.amazonaws.com.cn
|
2014-11-06 22:27:15 +00:00
|
|
|
fi
|
|
|
|
|
2015-03-12 14:36:24 +00:00
|
|
|
local -r staging_path="devel"
|
|
|
|
|
2015-06-04 13:08:04 +00:00
|
|
|
local -r local_dir="${KUBE_TEMP}/s3/"
|
|
|
|
mkdir ${local_dir}
|
2015-03-12 14:36:24 +00:00
|
|
|
|
2015-06-04 13:08:04 +00:00
|
|
|
echo "+++ Staging server tars to S3 Storage: ${AWS_S3_BUCKET}/${staging_path}"
|
2015-03-12 14:36:24 +00:00
|
|
|
local server_binary_path="${staging_path}/${SERVER_BINARY_TAR##*/}"
|
2015-06-04 13:08:04 +00:00
|
|
|
cp -a "${SERVER_BINARY_TAR}" ${local_dir}
|
|
|
|
cp -a "${SALT_TAR}" ${local_dir}
|
|
|
|
|
2015-08-01 18:06:13 +00:00
|
|
|
aws s3 sync --region ${s3_bucket_location} --exact-timestamps ${local_dir} "s3://${AWS_S3_BUCKET}/${staging_path}/"
|
2015-06-04 13:08:04 +00:00
|
|
|
|
2015-08-01 18:06:13 +00:00
|
|
|
aws s3api put-object-acl --region ${s3_bucket_location} --bucket ${AWS_S3_BUCKET} --key "${server_binary_path}" --grant-read 'uri="http://acs.amazonaws.com/groups/global/AllUsers"'
|
2015-03-12 14:36:24 +00:00
|
|
|
SERVER_BINARY_TAR_URL="${s3_url_base}/${AWS_S3_BUCKET}/${server_binary_path}"
|
2014-11-06 22:27:15 +00:00
|
|
|
|
2015-03-12 14:36:24 +00:00
|
|
|
local salt_tar_path="${staging_path}/${SALT_TAR##*/}"
|
2015-08-01 18:06:13 +00:00
|
|
|
aws s3api put-object-acl --region ${s3_bucket_location} --bucket ${AWS_S3_BUCKET} --key "${salt_tar_path}" --grant-read 'uri="http://acs.amazonaws.com/groups/global/AllUsers"'
|
2015-03-12 14:36:24 +00:00
|
|
|
SALT_TAR_URL="${s3_url_base}/${AWS_S3_BUCKET}/${salt_tar_path}"
|
2015-11-05 18:21:25 +00:00
|
|
|
|
|
|
|
echo "Uploaded server tars:"
|
|
|
|
echo " SERVER_BINARY_TAR_URL: ${SERVER_BINARY_TAR_URL}"
|
|
|
|
echo " SALT_TAR_URL: ${SALT_TAR_URL}"
|
2014-11-06 22:27:15 +00:00
|
|
|
}
|
|
|
|
|
2015-01-29 15:31:03 +00:00
|
|
|
# Adds a tag to an AWS resource
|
|
|
|
# usage: add-tag <resource-id> <tag-name> <tag-value>
|
|
|
|
function add-tag {
|
|
|
|
echo "Adding tag to ${1}: ${2}=${3}"
|
|
|
|
|
|
|
|
# We need to retry in case the resource isn't yet fully created
|
|
|
|
n=0
|
2015-06-12 22:29:31 +00:00
|
|
|
until [ $n -ge 25 ]; do
|
2015-01-29 15:31:03 +00:00
|
|
|
$AWS_CMD create-tags --resources ${1} --tags Key=${2},Value=${3} > $LOG && return
|
|
|
|
n=$[$n+1]
|
2015-06-12 22:29:31 +00:00
|
|
|
sleep 3
|
2015-01-29 15:31:03 +00:00
|
|
|
done
|
|
|
|
|
|
|
|
echo "Unable to add tag to AWS resource"
|
|
|
|
exit 1
|
|
|
|
}
|
|
|
|
|
2015-03-12 14:59:33 +00:00
|
|
|
# Creates the IAM profile, based on configuration files in templates/iam
|
|
|
|
function create-iam-profile {
|
|
|
|
local key=$1
|
|
|
|
|
|
|
|
local conf_dir=file://${KUBE_ROOT}/cluster/aws/templates/iam
|
|
|
|
|
|
|
|
echo "Creating IAM role: ${key}"
|
|
|
|
aws iam create-role --role-name ${key} --assume-role-policy-document ${conf_dir}/${key}-role.json > $LOG
|
|
|
|
|
|
|
|
echo "Creating IAM role-policy: ${key}"
|
|
|
|
aws iam put-role-policy --role-name ${key} --policy-name ${key} --policy-document ${conf_dir}/${key}-policy.json > $LOG
|
|
|
|
|
|
|
|
echo "Creating IAM instance-policy: ${key}"
|
|
|
|
aws iam create-instance-profile --instance-profile-name ${key} > $LOG
|
|
|
|
|
|
|
|
echo "Adding IAM role to instance-policy: ${key}"
|
|
|
|
aws iam add-role-to-instance-profile --instance-profile-name ${key} --role-name ${key} > $LOG
|
|
|
|
}
|
|
|
|
|
|
|
|
# Creates the IAM roles (if they do not already exist)
|
|
|
|
function ensure-iam-profiles {
|
|
|
|
aws iam get-instance-profile --instance-profile-name ${IAM_PROFILE_MASTER} || {
|
|
|
|
echo "Creating master IAM profile: ${IAM_PROFILE_MASTER}"
|
|
|
|
create-iam-profile ${IAM_PROFILE_MASTER}
|
|
|
|
}
|
2015-11-24 02:59:56 +00:00
|
|
|
aws iam get-instance-profile --instance-profile-name ${IAM_PROFILE_NODE} || {
|
|
|
|
echo "Creating minion IAM profile: ${IAM_PROFILE_NODE}"
|
|
|
|
create-iam-profile ${IAM_PROFILE_NODE}
|
2015-03-12 14:59:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-11 04:30:42 +00:00
|
|
|
# Wait for instance to be in specified state
|
|
|
|
function wait-for-instance-state {
|
2015-03-26 17:22:50 +00:00
|
|
|
instance_id=$1
|
2015-11-11 04:30:42 +00:00
|
|
|
state=$2
|
|
|
|
|
2015-03-26 17:22:50 +00:00
|
|
|
while true; do
|
2015-11-11 04:30:42 +00:00
|
|
|
instance_state=$($AWS_CMD describe-instances --instance-ids ${instance_id} --query Reservations[].Instances[].State.Name)
|
|
|
|
if [[ "$instance_state" == "${state}" ]]; then
|
2015-03-26 17:22:50 +00:00
|
|
|
break
|
|
|
|
else
|
2015-11-11 04:30:42 +00:00
|
|
|
echo "Waiting for instance ${instance_id} to be ${state} (currently ${instance_state})"
|
2015-03-26 17:22:50 +00:00
|
|
|
echo "Sleeping for 3 seconds..."
|
|
|
|
sleep 3
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
2015-05-08 15:01:04 +00:00
|
|
|
# Allocates new Elastic IP from Amazon
|
|
|
|
# Output: allocated IP address
|
2015-05-06 13:27:17 +00:00
|
|
|
function allocate-elastic-ip {
|
2015-11-11 04:30:42 +00:00
|
|
|
$AWS_CMD allocate-address --domain vpc --query PublicIp
|
2015-05-06 13:27:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function assign-ip-to-instance {
|
|
|
|
local ip_address=$1
|
|
|
|
local instance_id=$2
|
|
|
|
|
2015-11-11 04:30:42 +00:00
|
|
|
local elastic_ip_allocation_id=$($AWS_CMD describe-addresses --public-ips $ip_address --query Addresses[].AllocationId)
|
|
|
|
echo "Attaching IP ${ip_address} to instance ${instance_id}"
|
|
|
|
$AWS_CMD associate-address --instance-id ${instance_id} --allocation-id ${elastic_ip_allocation_id} > $LOG
|
2015-05-06 13:27:17 +00:00
|
|
|
}
|
|
|
|
|
2015-05-13 07:41:51 +00:00
|
|
|
# If MASTER_RESERVED_IP looks like IP address, will try to assign it to master instance
|
|
|
|
# If MASTER_RESERVED_IP is "auto", will allocate new elastic ip and assign that
|
|
|
|
# If none of the above or something fails, will output originally assigne IP
|
2015-05-08 15:01:04 +00:00
|
|
|
# Output: assigned IP address
|
2015-05-06 13:27:17 +00:00
|
|
|
function assign-elastic-ip {
|
|
|
|
local assigned_public_ip=$1
|
|
|
|
local master_instance_id=$2
|
|
|
|
|
2015-05-13 07:41:51 +00:00
|
|
|
# Check that MASTER_RESERVED_IP looks like an IPv4 address
|
|
|
|
if [[ "${MASTER_RESERVED_IP}" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
2015-05-08 15:01:04 +00:00
|
|
|
assign-ip-to-instance "${MASTER_RESERVED_IP}" "${master_instance_id}" "${assigned_public_ip}"
|
2015-05-13 07:41:51 +00:00
|
|
|
elif [[ "${MASTER_RESERVED_IP}" = "auto" ]]; then
|
2015-05-08 15:01:04 +00:00
|
|
|
assign-ip-to-instance $(allocate-elastic-ip) "${master_instance_id}" "${assigned_public_ip}"
|
2015-05-13 07:41:51 +00:00
|
|
|
else
|
|
|
|
echo "${assigned_public_ip}"
|
2015-05-06 13:27:17 +00:00
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2015-11-25 22:20:22 +00:00
|
|
|
function ssh-key-setup {
|
2015-03-25 19:41:02 +00:00
|
|
|
if [[ ! -f "$AWS_SSH_KEY" ]]; then
|
|
|
|
ssh-keygen -f "$AWS_SSH_KEY" -N ''
|
2014-11-06 22:27:15 +00:00
|
|
|
fi
|
2014-11-13 02:14:24 +00:00
|
|
|
|
2015-07-01 11:10:48 +00:00
|
|
|
# Note that we use get-ssh-fingerprint, so this works on OSX Mavericks
|
|
|
|
# get-aws-fingerprint gives the same fingerprint that AWS computes,
|
|
|
|
# but OSX Mavericks ssh-keygen can't compute it
|
|
|
|
AWS_SSH_KEY_FINGERPRINT=$(get-ssh-fingerprint ${AWS_SSH_KEY}.pub)
|
2015-06-04 18:16:23 +00:00
|
|
|
echo "Using SSH key with (AWS) fingerprint: ${AWS_SSH_KEY_FINGERPRINT}"
|
|
|
|
AWS_SSH_KEY_NAME="kubernetes-${AWS_SSH_KEY_FINGERPRINT//:/}"
|
|
|
|
|
|
|
|
import-public-key ${AWS_SSH_KEY_NAME} ${AWS_SSH_KEY}.pub
|
2015-11-25 22:20:22 +00:00
|
|
|
}
|
2014-11-26 15:18:26 +00:00
|
|
|
|
2015-11-25 22:20:22 +00:00
|
|
|
function vpc-setup {
|
2015-07-06 14:10:34 +00:00
|
|
|
if [[ -z "${VPC_ID:-}" ]]; then
|
|
|
|
VPC_ID=$(get_vpc_id)
|
|
|
|
fi
|
2015-03-25 19:36:20 +00:00
|
|
|
if [[ -z "$VPC_ID" ]]; then
|
2014-11-26 15:18:26 +00:00
|
|
|
echo "Creating vpc."
|
2015-11-11 04:30:42 +00:00
|
|
|
VPC_ID=$($AWS_CMD create-vpc --cidr-block ${VPC_CIDR} --query Vpc.VpcId)
|
2014-11-26 15:18:26 +00:00
|
|
|
$AWS_CMD modify-vpc-attribute --vpc-id $VPC_ID --enable-dns-support '{"Value": true}' > $LOG
|
|
|
|
$AWS_CMD modify-vpc-attribute --vpc-id $VPC_ID --enable-dns-hostnames '{"Value": true}' > $LOG
|
2015-01-29 15:31:03 +00:00
|
|
|
add-tag $VPC_ID Name kubernetes-vpc
|
2015-03-25 13:23:22 +00:00
|
|
|
add-tag $VPC_ID KubernetesCluster ${CLUSTER_ID}
|
2014-11-26 15:18:26 +00:00
|
|
|
fi
|
|
|
|
|
|
|
|
echo "Using VPC $VPC_ID"
|
2015-11-25 22:20:22 +00:00
|
|
|
}
|
2014-11-26 15:18:26 +00:00
|
|
|
|
2015-11-25 22:20:22 +00:00
|
|
|
function subnet-setup {
|
2015-07-06 14:10:34 +00:00
|
|
|
if [[ -z "${SUBNET_ID:-}" ]]; then
|
2015-11-03 15:08:46 +00:00
|
|
|
SUBNET_ID=$(get_subnet_id $VPC_ID $ZONE)
|
2015-07-06 14:10:34 +00:00
|
|
|
fi
|
2015-05-14 16:55:31 +00:00
|
|
|
|
2015-03-25 19:36:20 +00:00
|
|
|
if [[ -z "$SUBNET_ID" ]]; then
|
2015-04-23 09:01:17 +00:00
|
|
|
echo "Creating subnet."
|
2015-11-11 04:30:42 +00:00
|
|
|
SUBNET_ID=$($AWS_CMD create-subnet --cidr-block ${SUBNET_CIDR} --vpc-id $VPC_ID --availability-zone ${ZONE} --query Subnet.SubnetId)
|
2015-06-05 02:03:50 +00:00
|
|
|
add-tag $SUBNET_ID KubernetesCluster ${CLUSTER_ID}
|
2015-04-23 09:01:17 +00:00
|
|
|
else
|
2015-11-11 04:30:42 +00:00
|
|
|
EXISTING_CIDR=$($AWS_CMD describe-subnets --subnet-ids ${SUBNET_ID} --query Subnets[].CidrBlock)
|
2015-11-03 16:01:41 +00:00
|
|
|
echo "Using existing subnet with CIDR $EXISTING_CIDR"
|
2015-11-11 04:30:42 +00:00
|
|
|
VPC_CIDR=$($AWS_CMD describe-vpcs --vpc-ids ${VPC_ID} --query Vpcs[].CidrBlock)
|
2015-11-03 16:01:41 +00:00
|
|
|
echo "VPC CIDR is $VPC_CIDR"
|
|
|
|
VPC_CIDR_BASE=${VPC_CIDR%.*.*}
|
|
|
|
MASTER_INTERNAL_IP=${VPC_CIDR_BASE}.0${MASTER_IP_SUFFIX}
|
|
|
|
echo "Assuming MASTER_INTERNAL_IP=${MASTER_INTERNAL_IP}"
|
2014-11-26 15:18:26 +00:00
|
|
|
fi
|
|
|
|
|
|
|
|
echo "Using subnet $SUBNET_ID"
|
2015-11-25 22:20:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function kube-up {
|
|
|
|
echo "Starting cluster using os distro: ${KUBE_OS_DISTRIBUTION}" >&2
|
|
|
|
|
|
|
|
get-tokens
|
|
|
|
|
|
|
|
detect-image
|
|
|
|
detect-minion-image
|
|
|
|
|
|
|
|
find-release-tars
|
|
|
|
|
|
|
|
ensure-temp-dir
|
|
|
|
|
|
|
|
upload-server-tars
|
|
|
|
|
|
|
|
ensure-iam-profiles
|
|
|
|
|
|
|
|
load-or-gen-kube-basicauth
|
|
|
|
|
|
|
|
ssh-key-setup
|
|
|
|
|
|
|
|
vpc-setup
|
|
|
|
|
|
|
|
create-dhcp-option-set
|
|
|
|
|
|
|
|
subnet-setup
|
2014-11-26 15:18:26 +00:00
|
|
|
|
2015-11-03 15:08:46 +00:00
|
|
|
IGW_ID=$(get_igw_id $VPC_ID)
|
2015-03-25 19:36:20 +00:00
|
|
|
if [[ -z "$IGW_ID" ]]; then
|
2014-11-26 15:18:26 +00:00
|
|
|
echo "Creating Internet Gateway."
|
2015-11-11 04:30:42 +00:00
|
|
|
IGW_ID=$($AWS_CMD create-internet-gateway --query InternetGateway.InternetGatewayId)
|
2014-11-26 15:18:26 +00:00
|
|
|
$AWS_CMD attach-internet-gateway --internet-gateway-id $IGW_ID --vpc-id $VPC_ID > $LOG
|
2014-11-26 11:17:14 +00:00
|
|
|
fi
|
2014-11-26 15:18:26 +00:00
|
|
|
|
|
|
|
echo "Using Internet Gateway $IGW_ID"
|
|
|
|
|
|
|
|
echo "Associating route table."
|
2015-11-11 04:30:42 +00:00
|
|
|
ROUTE_TABLE_ID=$($AWS_CMD describe-route-tables \
|
2015-06-12 22:31:03 +00:00
|
|
|
--filters Name=vpc-id,Values=${VPC_ID} \
|
|
|
|
Name=tag:KubernetesCluster,Values=${CLUSTER_ID} \
|
|
|
|
--query RouteTables[].RouteTableId)
|
|
|
|
if [[ -z "${ROUTE_TABLE_ID}" ]]; then
|
|
|
|
echo "Creating route table"
|
2015-11-11 04:30:42 +00:00
|
|
|
ROUTE_TABLE_ID=$($AWS_CMD create-route-table \
|
2015-06-12 22:31:03 +00:00
|
|
|
--vpc-id=${VPC_ID} \
|
|
|
|
--query RouteTable.RouteTableId)
|
|
|
|
add-tag ${ROUTE_TABLE_ID} KubernetesCluster ${CLUSTER_ID}
|
|
|
|
fi
|
|
|
|
|
|
|
|
echo "Associating route table ${ROUTE_TABLE_ID} to subnet ${SUBNET_ID}"
|
2014-11-26 15:18:26 +00:00
|
|
|
$AWS_CMD associate-route-table --route-table-id $ROUTE_TABLE_ID --subnet-id $SUBNET_ID > $LOG || true
|
2015-06-12 22:31:03 +00:00
|
|
|
echo "Adding route to route table ${ROUTE_TABLE_ID}"
|
2014-11-26 15:18:26 +00:00
|
|
|
$AWS_CMD create-route --route-table-id $ROUTE_TABLE_ID --destination-cidr-block 0.0.0.0/0 --gateway-id $IGW_ID > $LOG || true
|
|
|
|
|
|
|
|
echo "Using Route Table $ROUTE_TABLE_ID"
|
|
|
|
|
2015-06-05 02:03:50 +00:00
|
|
|
# Create security groups
|
|
|
|
MASTER_SG_ID=$(get_security_group_id "${MASTER_SG_NAME}")
|
|
|
|
if [[ -z "${MASTER_SG_ID}" ]]; then
|
|
|
|
echo "Creating master security group."
|
|
|
|
create-security-group "${MASTER_SG_NAME}" "Kubernetes security group applied to master nodes"
|
|
|
|
fi
|
2015-11-24 03:05:33 +00:00
|
|
|
NODE_SG_ID=$(get_security_group_id "${NODE_SG_NAME}")
|
|
|
|
if [[ -z "${NODE_SG_ID}" ]]; then
|
2015-06-05 02:03:50 +00:00
|
|
|
echo "Creating minion security group."
|
2015-11-24 03:05:33 +00:00
|
|
|
create-security-group "${NODE_SG_NAME}" "Kubernetes security group applied to minion nodes"
|
2014-11-26 15:18:26 +00:00
|
|
|
fi
|
2015-06-05 02:03:50 +00:00
|
|
|
|
|
|
|
detect-security-groups
|
|
|
|
|
|
|
|
# Masters can talk to master
|
|
|
|
authorize-security-group-ingress "${MASTER_SG_ID}" "--source-group ${MASTER_SG_ID} --protocol all"
|
|
|
|
|
|
|
|
# Minions can talk to minions
|
2015-11-24 03:05:33 +00:00
|
|
|
authorize-security-group-ingress "${NODE_SG_ID}" "--source-group ${NODE_SG_ID} --protocol all"
|
2015-06-05 02:03:50 +00:00
|
|
|
|
|
|
|
# Masters and minions can talk to each other
|
2015-11-24 03:05:33 +00:00
|
|
|
authorize-security-group-ingress "${MASTER_SG_ID}" "--source-group ${NODE_SG_ID} --protocol all"
|
|
|
|
authorize-security-group-ingress "${NODE_SG_ID}" "--source-group ${MASTER_SG_ID} --protocol all"
|
2015-06-05 02:03:50 +00:00
|
|
|
|
|
|
|
# TODO(justinsb): Would be fairly easy to replace 0.0.0.0/0 in these rules
|
|
|
|
|
|
|
|
# SSH is open to the world
|
|
|
|
authorize-security-group-ingress "${MASTER_SG_ID}" "--protocol tcp --port 22 --cidr 0.0.0.0/0"
|
2015-11-24 03:05:33 +00:00
|
|
|
authorize-security-group-ingress "${NODE_SG_ID}" "--protocol tcp --port 22 --cidr 0.0.0.0/0"
|
2015-06-05 02:03:50 +00:00
|
|
|
|
|
|
|
# HTTPS to the master is allowed (for API access)
|
|
|
|
authorize-security-group-ingress "${MASTER_SG_ID}" "--protocol tcp --port 443 --cidr 0.0.0.0/0"
|
|
|
|
|
2015-11-03 16:01:41 +00:00
|
|
|
# KUBE_SHARE_MASTER is used to add minions to an existing master
|
|
|
|
if [[ "${KUBE_SHARE_MASTER:-}" == "true" ]]; then
|
|
|
|
# Detect existing master
|
|
|
|
detect-master
|
|
|
|
|
|
|
|
# Start minions
|
|
|
|
start-minions
|
2015-11-25 22:20:22 +00:00
|
|
|
wait-minions
|
2015-11-03 16:01:41 +00:00
|
|
|
else
|
|
|
|
# Create the master
|
|
|
|
start-master
|
2015-11-03 15:10:51 +00:00
|
|
|
|
2015-11-03 16:01:41 +00:00
|
|
|
# Start minions
|
|
|
|
start-minions
|
2015-11-25 22:20:22 +00:00
|
|
|
wait-minions
|
2015-11-03 15:10:51 +00:00
|
|
|
|
2015-11-03 16:01:41 +00:00
|
|
|
# Wait for the master to be ready
|
|
|
|
wait-master
|
2015-11-03 15:10:51 +00:00
|
|
|
|
2015-11-03 16:01:41 +00:00
|
|
|
# Build ~/.kube/config
|
|
|
|
build-config
|
|
|
|
fi
|
2015-11-03 15:10:51 +00:00
|
|
|
|
|
|
|
# Check the cluster is OK
|
|
|
|
check-cluster
|
|
|
|
}
|
|
|
|
|
|
|
|
# Starts the master node
|
|
|
|
function start-master() {
|
2015-06-25 20:00:04 +00:00
|
|
|
# Get or create master persistent volume
|
|
|
|
ensure-master-pd
|
2015-06-16 22:52:00 +00:00
|
|
|
|
2015-07-03 04:30:04 +00:00
|
|
|
# Determine extra certificate names for master
|
|
|
|
octets=($(echo "$SERVICE_CLUSTER_IP_RANGE" | sed -e 's|/.*||' -e 's/\./ /g'))
|
|
|
|
((octets[3]+=1))
|
|
|
|
service_ip=$(echo "${octets[*]}" | sed 's/ /./g')
|
|
|
|
MASTER_EXTRA_SANS="IP:${service_ip},DNS:kubernetes,DNS:kubernetes.default,DNS:kubernetes.default.svc,DNS:kubernetes.default.svc.${DNS_DOMAIN},DNS:${MASTER_NAME}"
|
|
|
|
|
|
|
|
|
2014-11-06 22:27:15 +00:00
|
|
|
(
|
|
|
|
# We pipe this to the ami as a startup script in the user-data field. Requires a compatible ami
|
|
|
|
echo "#! /bin/bash"
|
|
|
|
echo "mkdir -p /var/cache/kubernetes-install"
|
|
|
|
echo "cd /var/cache/kubernetes-install"
|
2015-03-03 17:18:12 +00:00
|
|
|
echo "readonly SALT_MASTER='${MASTER_INTERNAL_IP}'"
|
2015-02-13 22:58:42 +00:00
|
|
|
echo "readonly INSTANCE_PREFIX='${INSTANCE_PREFIX}'"
|
2015-06-13 04:34:43 +00:00
|
|
|
echo "readonly NODE_INSTANCE_PREFIX='${NODE_INSTANCE_PREFIX}'"
|
2015-06-12 16:33:17 +00:00
|
|
|
echo "readonly CLUSTER_IP_RANGE='${CLUSTER_IP_RANGE}'"
|
|
|
|
echo "readonly ALLOCATE_NODE_CIDRS='${ALLOCATE_NODE_CIDRS}'"
|
2015-03-12 14:36:24 +00:00
|
|
|
echo "readonly SERVER_BINARY_TAR_URL='${SERVER_BINARY_TAR_URL}'"
|
|
|
|
echo "readonly SALT_TAR_URL='${SALT_TAR_URL}'"
|
2015-03-27 15:53:17 +00:00
|
|
|
echo "readonly ZONE='${ZONE}'"
|
2015-05-02 19:37:54 +00:00
|
|
|
echo "readonly KUBE_USER='${KUBE_USER}'"
|
|
|
|
echo "readonly KUBE_PASSWORD='${KUBE_PASSWORD}'"
|
2015-05-24 05:17:55 +00:00
|
|
|
echo "readonly SERVICE_CLUSTER_IP_RANGE='${SERVICE_CLUSTER_IP_RANGE}'"
|
2015-06-01 07:12:41 +00:00
|
|
|
echo "readonly ENABLE_CLUSTER_MONITORING='${ENABLE_CLUSTER_MONITORING:-none}'"
|
Deferred creation of SkyDNS, monitoring and logging objects
This implements phase 1 of the proposal in #3579, moving the creation
of the pods, RCs, and services to the master after the apiserver is
available.
This is such a wide commit because our existing initial config story
is special:
* Add kube-addons service and associated salt configuration:
** We configure /etc/kubernetes/addons to be a directory of objects
that are appropriately configured for the current cluster.
** "/etc/init.d/kube-addons start" slurps up everything in that dir.
(Most of the difficult is the business logic in salt around getting
that directory built at all.)
** We cheat and overlay cluster/addons into saltbase/salt/kube-addons
as config files for the kube-addons meta-service.
* Change .yaml.in files to salt templates
* Rename {setup,teardown}-{monitoring,logging} to
{setup,teardown}-{monitoring,logging}-firewall to properly reflect
their real purpose now (the purpose of these functions is now ONLY to
bring up the firewall rules, and possibly to relay the IP to the user).
* Rework GCE {setup,teardown}-{monitoring,logging}-firewall: Both
functions were improperly configuring global rules, yet used
lifecycles tied to the cluster. Use $NODE_INSTANCE_PREFIX with the
rule. The logging rule needed a $NETWORK specifier. The monitoring
rule tried gcloud describe first, but given the instancing, this feels
like a waste of time now.
* Plumb ENABLE_CLUSTER_MONITORING, ENABLE_CLUSTER_LOGGING,
ELASTICSEARCH_LOGGING_REPLICAS and DNS_REPLICAS down to the master,
since these are needed there now.
(Desperately want just a yaml or json file we can share between
providers that has all this crap. Maybe #3525 is an answer?)
Huge caveats: I've gone pretty firm testing on GCE, including
twiddling the env variables and making sure the objects I expect to
come up, come up. I've tested that it doesn't break GKE bringup
somehow. But I haven't had a chance to test the other providers.
2015-01-18 23:16:52 +00:00
|
|
|
echo "readonly ENABLE_CLUSTER_LOGGING='${ENABLE_CLUSTER_LOGGING:-false}'"
|
2014-11-14 07:07:43 +00:00
|
|
|
echo "readonly ENABLE_NODE_LOGGING='${ENABLE_NODE_LOGGING:-false}'"
|
|
|
|
echo "readonly LOGGING_DESTINATION='${LOGGING_DESTINATION:-}'"
|
Deferred creation of SkyDNS, monitoring and logging objects
This implements phase 1 of the proposal in #3579, moving the creation
of the pods, RCs, and services to the master after the apiserver is
available.
This is such a wide commit because our existing initial config story
is special:
* Add kube-addons service and associated salt configuration:
** We configure /etc/kubernetes/addons to be a directory of objects
that are appropriately configured for the current cluster.
** "/etc/init.d/kube-addons start" slurps up everything in that dir.
(Most of the difficult is the business logic in salt around getting
that directory built at all.)
** We cheat and overlay cluster/addons into saltbase/salt/kube-addons
as config files for the kube-addons meta-service.
* Change .yaml.in files to salt templates
* Rename {setup,teardown}-{monitoring,logging} to
{setup,teardown}-{monitoring,logging}-firewall to properly reflect
their real purpose now (the purpose of these functions is now ONLY to
bring up the firewall rules, and possibly to relay the IP to the user).
* Rework GCE {setup,teardown}-{monitoring,logging}-firewall: Both
functions were improperly configuring global rules, yet used
lifecycles tied to the cluster. Use $NODE_INSTANCE_PREFIX with the
rule. The logging rule needed a $NETWORK specifier. The monitoring
rule tried gcloud describe first, but given the instancing, this feels
like a waste of time now.
* Plumb ENABLE_CLUSTER_MONITORING, ENABLE_CLUSTER_LOGGING,
ELASTICSEARCH_LOGGING_REPLICAS and DNS_REPLICAS down to the master,
since these are needed there now.
(Desperately want just a yaml or json file we can share between
providers that has all this crap. Maybe #3525 is an answer?)
Huge caveats: I've gone pretty firm testing on GCE, including
twiddling the env variables and making sure the objects I expect to
come up, come up. I've tested that it doesn't break GKE bringup
somehow. But I haven't had a chance to test the other providers.
2015-01-18 23:16:52 +00:00
|
|
|
echo "readonly ELASTICSEARCH_LOGGING_REPLICAS='${ELASTICSEARCH_LOGGING_REPLICAS:-}'"
|
2014-11-07 04:49:21 +00:00
|
|
|
echo "readonly ENABLE_CLUSTER_DNS='${ENABLE_CLUSTER_DNS:-false}'"
|
2015-07-23 18:30:53 +00:00
|
|
|
echo "readonly ENABLE_CLUSTER_UI='${ENABLE_CLUSTER_UI:-false}'"
|
2015-10-06 18:55:04 +00:00
|
|
|
echo "readonly RUNTIME_CONFIG='${RUNTIME_CONFIG}'"
|
Deferred creation of SkyDNS, monitoring and logging objects
This implements phase 1 of the proposal in #3579, moving the creation
of the pods, RCs, and services to the master after the apiserver is
available.
This is such a wide commit because our existing initial config story
is special:
* Add kube-addons service and associated salt configuration:
** We configure /etc/kubernetes/addons to be a directory of objects
that are appropriately configured for the current cluster.
** "/etc/init.d/kube-addons start" slurps up everything in that dir.
(Most of the difficult is the business logic in salt around getting
that directory built at all.)
** We cheat and overlay cluster/addons into saltbase/salt/kube-addons
as config files for the kube-addons meta-service.
* Change .yaml.in files to salt templates
* Rename {setup,teardown}-{monitoring,logging} to
{setup,teardown}-{monitoring,logging}-firewall to properly reflect
their real purpose now (the purpose of these functions is now ONLY to
bring up the firewall rules, and possibly to relay the IP to the user).
* Rework GCE {setup,teardown}-{monitoring,logging}-firewall: Both
functions were improperly configuring global rules, yet used
lifecycles tied to the cluster. Use $NODE_INSTANCE_PREFIX with the
rule. The logging rule needed a $NETWORK specifier. The monitoring
rule tried gcloud describe first, but given the instancing, this feels
like a waste of time now.
* Plumb ENABLE_CLUSTER_MONITORING, ENABLE_CLUSTER_LOGGING,
ELASTICSEARCH_LOGGING_REPLICAS and DNS_REPLICAS down to the master,
since these are needed there now.
(Desperately want just a yaml or json file we can share between
providers that has all this crap. Maybe #3525 is an answer?)
Huge caveats: I've gone pretty firm testing on GCE, including
twiddling the env variables and making sure the objects I expect to
come up, come up. I've tested that it doesn't break GKE bringup
somehow. But I haven't had a chance to test the other providers.
2015-01-18 23:16:52 +00:00
|
|
|
echo "readonly DNS_REPLICAS='${DNS_REPLICAS:-}'"
|
2014-11-07 04:49:21 +00:00
|
|
|
echo "readonly DNS_SERVER_IP='${DNS_SERVER_IP:-}'"
|
|
|
|
echo "readonly DNS_DOMAIN='${DNS_DOMAIN:-}'"
|
2015-03-25 00:19:06 +00:00
|
|
|
echo "readonly ADMISSION_CONTROL='${ADMISSION_CONTROL:-}'"
|
|
|
|
echo "readonly MASTER_IP_RANGE='${MASTER_IP_RANGE:-}'"
|
2015-05-13 20:39:22 +00:00
|
|
|
echo "readonly KUBELET_TOKEN='${KUBELET_TOKEN}'"
|
|
|
|
echo "readonly KUBE_PROXY_TOKEN='${KUBE_PROXY_TOKEN}'"
|
2015-06-05 02:39:10 +00:00
|
|
|
echo "readonly DOCKER_STORAGE='${DOCKER_STORAGE:-}'"
|
2015-07-03 04:30:04 +00:00
|
|
|
echo "readonly MASTER_EXTRA_SANS='${MASTER_EXTRA_SANS:-}'"
|
2015-10-03 15:03:02 +00:00
|
|
|
echo "readonly NETWORK_PROVIDER='${NETWORK_PROVIDER:-}'"
|
|
|
|
echo "readonly OPENCONTRAIL_TAG='${OPENCONTRAIL_TAG:-}'"
|
|
|
|
echo "readonly OPENCONTRAIL_KUBERNETES_TAG='${OPENCONTRAIL_KUBERNETES_TAG:-}'"
|
|
|
|
echo "readonly OPENCONTRAIL_PUBLIC_SUBNET='${OPENCONTRAIL_PUBLIC_SUBNET:-}'"
|
2015-10-29 10:03:34 +00:00
|
|
|
echo "readonly E2E_STORAGE_TEST_ENVIRONMENT='${E2E_STORAGE_TEST_ENVIRONMENT:-}'"
|
2015-03-04 04:18:29 +00:00
|
|
|
grep -v "^#" "${KUBE_ROOT}/cluster/aws/templates/common.sh"
|
2015-03-19 17:05:58 +00:00
|
|
|
grep -v "^#" "${KUBE_ROOT}/cluster/aws/templates/format-disks.sh"
|
2015-06-25 20:00:04 +00:00
|
|
|
grep -v "^#" "${KUBE_ROOT}/cluster/aws/templates/setup-master-pd.sh"
|
2014-11-06 22:27:15 +00:00
|
|
|
grep -v "^#" "${KUBE_ROOT}/cluster/aws/templates/create-dynamic-salt-files.sh"
|
|
|
|
grep -v "^#" "${KUBE_ROOT}/cluster/aws/templates/download-release.sh"
|
|
|
|
grep -v "^#" "${KUBE_ROOT}/cluster/aws/templates/salt-master.sh"
|
|
|
|
) > "${KUBE_TEMP}/master-start.sh"
|
|
|
|
|
2014-11-26 15:18:26 +00:00
|
|
|
echo "Starting Master"
|
2014-11-06 22:27:15 +00:00
|
|
|
master_id=$($AWS_CMD run-instances \
|
2015-03-12 13:35:36 +00:00
|
|
|
--image-id $AWS_IMAGE \
|
2015-03-12 14:59:33 +00:00
|
|
|
--iam-instance-profile Name=$IAM_PROFILE_MASTER \
|
2014-09-09 10:17:32 +00:00
|
|
|
--instance-type $MASTER_SIZE \
|
|
|
|
--subnet-id $SUBNET_ID \
|
2015-04-23 09:01:17 +00:00
|
|
|
--private-ip-address $MASTER_INTERNAL_IP \
|
2015-06-04 18:16:23 +00:00
|
|
|
--key-name ${AWS_SSH_KEY_NAME} \
|
2015-06-05 02:03:50 +00:00
|
|
|
--security-group-ids ${MASTER_SG_ID} \
|
2014-09-09 10:17:32 +00:00
|
|
|
--associate-public-ip-address \
|
2015-08-18 18:03:23 +00:00
|
|
|
--block-device-mappings "${MASTER_BLOCK_DEVICE_MAPPINGS}" \
|
2015-11-11 04:30:42 +00:00
|
|
|
--user-data file://${KUBE_TEMP}/master-start.sh \
|
|
|
|
--query Instances[].InstanceId)
|
2015-01-29 15:31:03 +00:00
|
|
|
add-tag $master_id Name $MASTER_NAME
|
|
|
|
add-tag $master_id Role $MASTER_TAG
|
2015-03-25 13:23:22 +00:00
|
|
|
add-tag $master_id KubernetesCluster ${CLUSTER_ID}
|
2014-09-09 10:17:32 +00:00
|
|
|
|
2015-02-11 17:50:47 +00:00
|
|
|
echo "Waiting for master to be ready"
|
|
|
|
local attempt=0
|
|
|
|
|
2015-06-25 20:00:04 +00:00
|
|
|
while true; do
|
2015-02-11 17:50:47 +00:00
|
|
|
echo -n Attempt "$(($attempt+1))" to check for master node
|
2015-06-13 04:34:43 +00:00
|
|
|
local ip=$(get_instance_public_ip ${master_id})
|
2015-02-11 17:50:47 +00:00
|
|
|
if [[ -z "${ip}" ]]; then
|
|
|
|
if (( attempt > 30 )); then
|
|
|
|
echo
|
|
|
|
echo -e "${color_red}master failed to start. Your cluster is unlikely" >&2
|
|
|
|
echo "to work correctly. Please run ./cluster/kube-down.sh and re-create the" >&2
|
|
|
|
echo -e "cluster. (sorry!)${color_norm}" >&2
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
else
|
2015-08-23 11:39:01 +00:00
|
|
|
# We are not able to add an elastic ip, a route or volume to the instance until that instance is in "running" state.
|
2015-11-11 04:30:42 +00:00
|
|
|
wait-for-instance-state ${master_id} "running"
|
2015-08-23 11:39:01 +00:00
|
|
|
|
2015-02-11 17:50:47 +00:00
|
|
|
KUBE_MASTER=${MASTER_NAME}
|
2015-05-06 13:27:17 +00:00
|
|
|
KUBE_MASTER_IP=$(assign-elastic-ip $ip $master_id)
|
2015-03-26 17:26:23 +00:00
|
|
|
echo -e " ${color_green}[master running @${KUBE_MASTER_IP}]${color_norm}"
|
|
|
|
|
2015-06-25 20:00:04 +00:00
|
|
|
# This is a race between instance start and volume attachment. There appears to be no way to start an AWS instance with a volume attached.
|
2015-06-26 14:41:03 +00:00
|
|
|
# To work around this, we wait for volume to be ready in setup-master-pd.sh
|
2015-08-08 21:29:57 +00:00
|
|
|
echo "Attaching persistent data volume (${MASTER_DISK_ID}) to master"
|
2015-06-25 20:00:04 +00:00
|
|
|
$AWS_CMD attach-volume --volume-id ${MASTER_DISK_ID} --device /dev/sdb --instance-id ${master_id}
|
|
|
|
|
2015-03-26 17:22:50 +00:00
|
|
|
sleep 10
|
2015-03-25 03:49:55 +00:00
|
|
|
$AWS_CMD create-route --route-table-id $ROUTE_TABLE_ID --destination-cidr-block ${MASTER_IP_RANGE} --instance-id $master_id > $LOG
|
2015-02-11 17:50:47 +00:00
|
|
|
|
|
|
|
break
|
|
|
|
fi
|
|
|
|
echo -e " ${color_yellow}[master not working yet]${color_norm}"
|
|
|
|
attempt=$(($attempt+1))
|
|
|
|
sleep 10
|
|
|
|
done
|
|
|
|
|
2015-06-06 18:26:12 +00:00
|
|
|
# Check for SSH connectivity
|
|
|
|
attempt=0
|
|
|
|
while true; do
|
|
|
|
echo -n Attempt "$(($attempt+1))" to check for SSH to master
|
|
|
|
local output
|
|
|
|
local ok=1
|
2015-06-12 20:32:14 +00:00
|
|
|
output=$(ssh -oStrictHostKeyChecking=no -i "${AWS_SSH_KEY}" ${SSH_USER}@${KUBE_MASTER_IP} uptime 2> $LOG) || ok=0
|
2015-06-06 18:26:12 +00:00
|
|
|
if [[ ${ok} == 0 ]]; then
|
|
|
|
if (( attempt > 30 )); then
|
|
|
|
echo
|
|
|
|
echo "(Failed) output was: ${output}"
|
|
|
|
echo
|
|
|
|
echo -e "${color_red}Unable to ssh to master on ${KUBE_MASTER_IP}. Your cluster is unlikely" >&2
|
|
|
|
echo "to work correctly. Please run ./cluster/kube-down.sh and re-create the" >&2
|
|
|
|
echo -e "cluster. (sorry!)${color_norm}" >&2
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
else
|
|
|
|
echo -e " ${color_green}[ssh to master working]${color_norm}"
|
|
|
|
break
|
|
|
|
fi
|
|
|
|
echo -e " ${color_yellow}[ssh to master not working yet]${color_norm}"
|
|
|
|
attempt=$(($attempt+1))
|
|
|
|
sleep 10
|
|
|
|
done
|
|
|
|
|
2015-02-11 17:50:47 +00:00
|
|
|
# We need the salt-master to be up for the minions to work
|
|
|
|
attempt=0
|
|
|
|
while true; do
|
|
|
|
echo -n Attempt "$(($attempt+1))" to check for salt-master
|
|
|
|
local output
|
2015-06-06 18:26:12 +00:00
|
|
|
local ok=1
|
2015-06-12 20:32:14 +00:00
|
|
|
output=$(ssh -oStrictHostKeyChecking=no -i "${AWS_SSH_KEY}" ${SSH_USER}@${KUBE_MASTER_IP} pgrep salt-master 2> $LOG) || ok=0
|
2015-06-06 18:26:12 +00:00
|
|
|
if [[ ${ok} == 0 ]]; then
|
2015-02-11 17:50:47 +00:00
|
|
|
if (( attempt > 30 )); then
|
2015-06-06 18:26:12 +00:00
|
|
|
echo
|
|
|
|
echo "(Failed) output was: ${output}"
|
2015-02-11 17:50:47 +00:00
|
|
|
echo
|
|
|
|
echo -e "${color_red}salt-master failed to start on ${KUBE_MASTER_IP}. Your cluster is unlikely" >&2
|
|
|
|
echo "to work correctly. Please run ./cluster/kube-down.sh and re-create the" >&2
|
|
|
|
echo -e "cluster. (sorry!)${color_norm}" >&2
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
else
|
|
|
|
echo -e " ${color_green}[salt-master running]${color_norm}"
|
|
|
|
break
|
|
|
|
fi
|
|
|
|
echo -e " ${color_yellow}[salt-master not working yet]${color_norm}"
|
|
|
|
attempt=$(($attempt+1))
|
|
|
|
sleep 10
|
|
|
|
done
|
2015-11-03 15:10:51 +00:00
|
|
|
}
|
2015-02-11 17:50:47 +00:00
|
|
|
|
2015-11-03 15:10:51 +00:00
|
|
|
# Creates an ASG for the minion nodes
|
|
|
|
function start-minions() {
|
2015-06-13 04:34:43 +00:00
|
|
|
echo "Creating minion configuration"
|
|
|
|
generate-minion-user-data > "${KUBE_TEMP}/minion-user-data"
|
|
|
|
local public_ip_option
|
2015-11-24 03:01:03 +00:00
|
|
|
if [[ "${ENABLE_NODE_PUBLIC_IP}" == "true" ]]; then
|
2015-06-13 04:34:43 +00:00
|
|
|
public_ip_option="--associate-public-ip-address"
|
|
|
|
else
|
|
|
|
public_ip_option="--no-associate-public-ip-address"
|
|
|
|
fi
|
|
|
|
${AWS_ASG_CMD} create-launch-configuration \
|
|
|
|
--launch-configuration-name ${ASG_NAME} \
|
2015-11-24 03:00:37 +00:00
|
|
|
--image-id $KUBE_NODE_IMAGE \
|
2015-11-24 02:59:56 +00:00
|
|
|
--iam-instance-profile ${IAM_PROFILE_NODE} \
|
2015-11-24 03:05:51 +00:00
|
|
|
--instance-type $NODE_SIZE \
|
2015-06-04 18:16:23 +00:00
|
|
|
--key-name ${AWS_SSH_KEY_NAME} \
|
2015-11-24 03:05:33 +00:00
|
|
|
--security-groups ${NODE_SG_ID} \
|
2015-05-07 22:09:47 +00:00
|
|
|
${public_ip_option} \
|
2015-11-24 03:01:03 +00:00
|
|
|
--block-device-mappings "${NODE_BLOCK_DEVICE_MAPPINGS}" \
|
2015-06-13 04:34:43 +00:00
|
|
|
--user-data "file://${KUBE_TEMP}/minion-user-data"
|
|
|
|
|
|
|
|
echo "Creating autoscaling group"
|
|
|
|
${AWS_ASG_CMD} create-auto-scaling-group \
|
|
|
|
--auto-scaling-group-name ${ASG_NAME} \
|
|
|
|
--launch-configuration-name ${ASG_NAME} \
|
2015-11-24 03:06:36 +00:00
|
|
|
--min-size ${NUM_NODES} \
|
|
|
|
--max-size ${NUM_NODES} \
|
2015-06-13 04:34:43 +00:00
|
|
|
--vpc-zone-identifier ${SUBNET_ID} \
|
|
|
|
--tags ResourceId=${ASG_NAME},ResourceType=auto-scaling-group,Key=Name,Value=${NODE_INSTANCE_PREFIX} \
|
2015-11-24 03:06:00 +00:00
|
|
|
ResourceId=${ASG_NAME},ResourceType=auto-scaling-group,Key=Role,Value=${NODE_TAG} \
|
2015-06-13 04:34:43 +00:00
|
|
|
ResourceId=${ASG_NAME},ResourceType=auto-scaling-group,Key=KubernetesCluster,Value=${CLUSTER_ID}
|
2015-11-25 22:20:22 +00:00
|
|
|
}
|
2015-06-13 04:34:43 +00:00
|
|
|
|
2015-11-25 22:20:22 +00:00
|
|
|
function wait-minions {
|
2015-06-13 04:34:43 +00:00
|
|
|
# Wait for the minions to be running
|
|
|
|
# TODO(justinsb): This is really not needed any more
|
|
|
|
attempt=0
|
|
|
|
while true; do
|
|
|
|
find-running-minions > $LOG
|
2015-11-24 03:06:36 +00:00
|
|
|
if [[ ${#NODE_IDS[@]} == ${NUM_NODES} ]]; then
|
2015-11-24 03:02:38 +00:00
|
|
|
echo -e " ${color_green}${#NODE_IDS[@]} minions started; ready${color_norm}"
|
2015-06-13 04:34:43 +00:00
|
|
|
break
|
|
|
|
fi
|
2014-11-13 02:14:24 +00:00
|
|
|
|
2015-06-13 04:34:43 +00:00
|
|
|
if (( attempt > 30 )); then
|
|
|
|
echo
|
|
|
|
echo "Expected number of minions did not start in time"
|
|
|
|
echo
|
|
|
|
echo -e "${color_red}Expected number of minions failed to start. Your cluster is unlikely" >&2
|
|
|
|
echo "to work correctly. Please run ./cluster/kube-down.sh and re-create the" >&2
|
|
|
|
echo -e "cluster. (sorry!)${color_norm}" >&2
|
|
|
|
exit 1
|
|
|
|
fi
|
2014-11-06 22:27:15 +00:00
|
|
|
|
2015-11-24 03:02:38 +00:00
|
|
|
echo -e " ${color_yellow}${#NODE_IDS[@]} minions started; waiting${color_norm}"
|
2015-06-13 04:34:43 +00:00
|
|
|
attempt=$(($attempt+1))
|
2015-03-26 17:22:50 +00:00
|
|
|
sleep 10
|
2014-11-06 22:27:15 +00:00
|
|
|
done
|
2015-11-03 15:10:51 +00:00
|
|
|
}
|
2014-09-09 10:17:32 +00:00
|
|
|
|
2015-11-03 15:10:51 +00:00
|
|
|
# Wait for the master to be started
|
|
|
|
function wait-master() {
|
2014-11-26 15:18:26 +00:00
|
|
|
detect-master > $LOG
|
2014-09-09 10:17:32 +00:00
|
|
|
|
2015-06-13 04:34:43 +00:00
|
|
|
# TODO(justinsb): This is really not necessary any more
|
2014-11-13 02:14:24 +00:00
|
|
|
# Wait 3 minutes for cluster to come up. We hit it with a "highstate" after that to
|
2014-11-06 22:27:15 +00:00
|
|
|
# make sure that everything is well configured.
|
2015-01-30 02:08:27 +00:00
|
|
|
# TODO: Can we poll here?
|
|
|
|
echo "Waiting 3 minutes for cluster to settle"
|
2014-11-06 22:27:15 +00:00
|
|
|
local i
|
|
|
|
for (( i=0; i < 6*3; i++)); do
|
|
|
|
printf "."
|
|
|
|
sleep 10
|
|
|
|
done
|
|
|
|
echo "Re-running salt highstate"
|
2015-06-06 17:19:37 +00:00
|
|
|
ssh -oStrictHostKeyChecking=no -i "${AWS_SSH_KEY}" ${SSH_USER}@${KUBE_MASTER_IP} sudo salt '*' state.highstate > $LOG
|
2014-11-13 02:14:24 +00:00
|
|
|
|
2014-11-06 22:27:15 +00:00
|
|
|
echo "Waiting for cluster initialization."
|
|
|
|
echo
|
|
|
|
echo " This will continually check to see if the API for kubernetes is reachable."
|
|
|
|
echo " This might loop forever if there was some uncaught error during start"
|
|
|
|
echo " up."
|
|
|
|
echo
|
|
|
|
|
|
|
|
until $(curl --insecure --user ${KUBE_USER}:${KUBE_PASSWORD} --max-time 5 \
|
2015-05-13 18:01:35 +00:00
|
|
|
--fail --output $LOG --silent https://${KUBE_MASTER_IP}/healthz); do
|
2014-11-06 22:27:15 +00:00
|
|
|
printf "."
|
|
|
|
sleep 2
|
|
|
|
done
|
2014-09-09 10:17:32 +00:00
|
|
|
|
2014-11-06 22:27:15 +00:00
|
|
|
echo "Kubernetes cluster created."
|
2015-11-03 15:10:51 +00:00
|
|
|
}
|
2014-09-09 10:17:32 +00:00
|
|
|
|
2015-11-03 15:10:51 +00:00
|
|
|
# Creates the ~/.kube/config file, getting the information from the master
|
|
|
|
# The master much be running and set in KUBE_MASTER_IP
|
|
|
|
function build-config() {
|
2015-03-03 17:24:56 +00:00
|
|
|
# TODO use token instead of kube_auth
|
2015-04-10 00:07:24 +00:00
|
|
|
export KUBE_CERT="/tmp/$RANDOM-kubecfg.crt"
|
|
|
|
export KUBE_KEY="/tmp/$RANDOM-kubecfg.key"
|
|
|
|
export CA_CERT="/tmp/$RANDOM-kubernetes.ca.crt"
|
|
|
|
export CONTEXT="aws_${INSTANCE_PREFIX}"
|
2014-09-09 10:17:32 +00:00
|
|
|
|
2015-03-03 17:24:56 +00:00
|
|
|
local kubectl="${KUBE_ROOT}/cluster/kubectl.sh"
|
2014-11-06 22:27:15 +00:00
|
|
|
|
|
|
|
# TODO: generate ADMIN (and KUBELET) tokens and put those in the master's
|
|
|
|
# config file. Distribute the same way the htpasswd is done.
|
|
|
|
(
|
|
|
|
umask 077
|
2015-06-06 17:19:37 +00:00
|
|
|
ssh -oStrictHostKeyChecking=no -i "${AWS_SSH_KEY}" "${SSH_USER}@${KUBE_MASTER_IP}" sudo cat /srv/kubernetes/kubecfg.crt >"${KUBE_CERT}" 2>"$LOG"
|
|
|
|
ssh -oStrictHostKeyChecking=no -i "${AWS_SSH_KEY}" "${SSH_USER}@${KUBE_MASTER_IP}" sudo cat /srv/kubernetes/kubecfg.key >"${KUBE_KEY}" 2>"$LOG"
|
|
|
|
ssh -oStrictHostKeyChecking=no -i "${AWS_SSH_KEY}" "${SSH_USER}@${KUBE_MASTER_IP}" sudo cat /srv/kubernetes/ca.crt >"${CA_CERT}" 2>"$LOG"
|
2014-09-09 10:17:32 +00:00
|
|
|
|
2015-04-10 00:07:24 +00:00
|
|
|
create-kubeconfig
|
2014-11-06 22:27:15 +00:00
|
|
|
)
|
2015-11-03 15:10:51 +00:00
|
|
|
}
|
2015-03-03 17:24:56 +00:00
|
|
|
|
2015-11-03 15:10:51 +00:00
|
|
|
# Sanity check the cluster and print confirmation messages
|
|
|
|
function check-cluster() {
|
2015-03-03 17:24:56 +00:00
|
|
|
echo "Sanity checking cluster..."
|
|
|
|
|
|
|
|
sleep 5
|
|
|
|
|
2015-11-09 07:33:06 +00:00
|
|
|
detect-nodes > $LOG
|
2015-11-03 16:01:41 +00:00
|
|
|
|
2015-03-03 17:24:56 +00:00
|
|
|
# Don't bail on errors, we want to be able to print some info.
|
|
|
|
set +e
|
|
|
|
|
|
|
|
# Basic sanity checking
|
2015-06-13 04:34:43 +00:00
|
|
|
# TODO(justinsb): This is really not needed any more
|
2015-03-03 17:24:56 +00:00
|
|
|
local rc # Capture return code without exiting because of errexit bash option
|
2015-11-24 03:00:46 +00:00
|
|
|
for (( i=0; i<${#KUBE_NODE_IP_ADDRESSES[@]}; i++)); do
|
2015-03-03 17:24:56 +00:00
|
|
|
# Make sure docker is installed and working.
|
|
|
|
local attempt=0
|
|
|
|
while true; do
|
2015-11-24 03:00:46 +00:00
|
|
|
local minion_ip=${KUBE_NODE_IP_ADDRESSES[$i]}
|
2015-06-13 04:34:43 +00:00
|
|
|
echo -n "Attempt $(($attempt+1)) to check Docker on node @ ${minion_ip} ..."
|
|
|
|
local output=`check-minion ${minion_ip}`
|
2015-05-13 20:39:22 +00:00
|
|
|
echo $output
|
|
|
|
if [[ "${output}" != "working" ]]; then
|
2015-03-03 17:24:56 +00:00
|
|
|
if (( attempt > 9 )); then
|
|
|
|
echo
|
2015-05-23 07:12:24 +00:00
|
|
|
echo -e "${color_red}Your cluster is unlikely to work correctly." >&2
|
2015-05-13 20:39:22 +00:00
|
|
|
echo "Please run ./cluster/kube-down.sh and re-create the" >&2
|
2015-05-23 07:12:24 +00:00
|
|
|
echo -e "cluster. (sorry!)${color_norm}" >&2
|
2015-03-03 17:24:56 +00:00
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
else
|
|
|
|
break
|
|
|
|
fi
|
|
|
|
attempt=$(($attempt+1))
|
|
|
|
sleep 30
|
|
|
|
done
|
|
|
|
done
|
|
|
|
|
2015-08-22 01:47:31 +00:00
|
|
|
# ensures KUBECONFIG is set
|
|
|
|
get-kubeconfig-basicauth
|
2015-03-03 17:24:56 +00:00
|
|
|
echo
|
|
|
|
echo -e "${color_green}Kubernetes cluster is running. The master is running at:"
|
|
|
|
echo
|
|
|
|
echo -e "${color_yellow} https://${KUBE_MASTER_IP}"
|
|
|
|
echo
|
2015-04-10 00:07:24 +00:00
|
|
|
echo -e "${color_green}The user name and password to use is located in ${KUBECONFIG}.${color_norm}"
|
2015-03-03 17:24:56 +00:00
|
|
|
echo
|
2014-09-09 10:17:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function kube-down {
|
2015-04-23 01:30:09 +00:00
|
|
|
local vpc_id=$(get_vpc_id)
|
2015-02-11 17:50:47 +00:00
|
|
|
if [[ -n "${vpc_id}" ]]; then
|
2015-03-25 16:52:44 +00:00
|
|
|
local elb_ids=$(get_elbs_in_vpc ${vpc_id})
|
2015-04-23 01:30:09 +00:00
|
|
|
if [[ -n "${elb_ids}" ]]; then
|
2015-03-25 16:52:44 +00:00
|
|
|
echo "Deleting ELBs in: ${vpc_id}"
|
|
|
|
for elb_id in ${elb_ids}; do
|
2015-11-11 04:30:42 +00:00
|
|
|
aws elb delete-load-balancer --load-balancer-name=${elb_id} >$LOG
|
2015-03-25 16:52:44 +00:00
|
|
|
done
|
|
|
|
|
|
|
|
echo "Waiting for ELBs to be deleted"
|
|
|
|
while true; do
|
|
|
|
elb_ids=$(get_elbs_in_vpc ${vpc_id})
|
|
|
|
if [[ -z "$elb_ids" ]]; then
|
|
|
|
echo "All ELBs deleted"
|
|
|
|
break
|
|
|
|
else
|
|
|
|
echo "ELBs not yet deleted: $elb_ids"
|
|
|
|
echo "Sleeping for 3 seconds..."
|
|
|
|
sleep 3
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
fi
|
2015-03-25 12:36:47 +00:00
|
|
|
|
2015-03-25 13:23:22 +00:00
|
|
|
echo "Deleting instances in VPC: ${vpc_id}"
|
2015-11-11 04:30:42 +00:00
|
|
|
instance_ids=$($AWS_CMD describe-instances \
|
2015-03-25 13:23:22 +00:00
|
|
|
--filters Name=vpc-id,Values=${vpc_id} \
|
|
|
|
Name=tag:KubernetesCluster,Values=${CLUSTER_ID} \
|
|
|
|
--query Reservations[].Instances[].InstanceId)
|
2015-11-03 16:50:50 +00:00
|
|
|
|
2015-04-23 01:30:09 +00:00
|
|
|
if [[ -n "${instance_ids}" ]]; then
|
2015-11-11 04:30:42 +00:00
|
|
|
asg_groups=$($AWS_CMD describe-instances \
|
2015-11-06 15:39:42 +00:00
|
|
|
--query 'Reservations[].Instances[].Tags[?Key==`aws:autoscaling:groupName`].Value[]' \
|
|
|
|
--instance-ids ${instance_ids})
|
|
|
|
for asg_group in ${asg_groups}; do
|
2015-11-11 04:30:42 +00:00
|
|
|
if [[ -n $(${AWS_ASG_CMD} describe-auto-scaling-groups --auto-scaling-group-names ${asg_group} --query AutoScalingGroups[].AutoScalingGroupName) ]]; then
|
2015-11-06 15:39:42 +00:00
|
|
|
echo "Deleting auto-scaling group: ${asg_group}"
|
|
|
|
${AWS_ASG_CMD} delete-auto-scaling-group --force-delete --auto-scaling-group-name ${asg_group}
|
|
|
|
fi
|
2015-11-11 04:30:42 +00:00
|
|
|
if [[ -n $(${AWS_ASG_CMD} describe-launch-configurations --launch-configuration-names ${asg_group} --query LaunchConfigurations[].LaunchConfigurationName) ]]; then
|
2015-11-06 15:39:42 +00:00
|
|
|
echo "Deleting auto-scaling launch configuration: ${asg_group}"
|
|
|
|
${AWS_ASG_CMD} delete-launch-configuration --launch-configuration-name ${asg_group}
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
|
2015-04-23 01:30:09 +00:00
|
|
|
$AWS_CMD terminate-instances --instance-ids ${instance_ids} > $LOG
|
2015-03-25 13:23:22 +00:00
|
|
|
echo "Waiting for instances to be deleted"
|
2015-11-11 04:30:42 +00:00
|
|
|
for instance_id in ${instance_ids}; do
|
|
|
|
wait-for-instance-state ${instance_id} "terminated"
|
2015-03-25 13:23:22 +00:00
|
|
|
done
|
2015-11-11 04:30:42 +00:00
|
|
|
echo "All instances deleted"
|
2015-03-25 13:23:22 +00:00
|
|
|
fi
|
|
|
|
|
2015-11-11 04:30:42 +00:00
|
|
|
echo "Cleaning up resources in VPC: ${vpc_id}"
|
|
|
|
default_sg_id=$($AWS_CMD describe-security-groups \
|
2015-06-05 02:03:50 +00:00
|
|
|
--filters Name=vpc-id,Values=${vpc_id} \
|
|
|
|
Name=group-name,Values=default \
|
2015-03-23 20:00:34 +00:00
|
|
|
--query SecurityGroups[].GroupId \
|
|
|
|
| tr "\t" "\n")
|
2015-11-11 04:30:42 +00:00
|
|
|
sg_ids=$($AWS_CMD describe-security-groups \
|
2015-04-23 01:30:09 +00:00
|
|
|
--filters Name=vpc-id,Values=${vpc_id} \
|
2015-06-05 02:03:50 +00:00
|
|
|
Name=tag:KubernetesCluster,Values=${CLUSTER_ID} \
|
2015-03-23 20:00:34 +00:00
|
|
|
--query SecurityGroups[].GroupId \
|
|
|
|
| tr "\t" "\n")
|
2015-06-05 02:03:50 +00:00
|
|
|
# First delete any inter-security group ingress rules
|
|
|
|
# (otherwise we get dependency violations)
|
2015-03-23 20:00:34 +00:00
|
|
|
for sg_id in ${sg_ids}; do
|
|
|
|
# EC2 doesn't let us delete the default security group
|
2015-06-05 02:03:50 +00:00
|
|
|
if [[ "${sg_id}" == "${default_sg_id}" ]]; then
|
|
|
|
continue
|
2015-03-23 20:00:34 +00:00
|
|
|
fi
|
2015-06-05 02:03:50 +00:00
|
|
|
|
|
|
|
echo "Cleaning up security group: ${sg_id}"
|
2015-11-11 04:30:42 +00:00
|
|
|
other_sgids=$(${AWS_CMD} describe-security-groups --group-id "${sg_id}" --query SecurityGroups[].IpPermissions[].UserIdGroupPairs[].GroupId)
|
2015-06-05 02:03:50 +00:00
|
|
|
for other_sgid in ${other_sgids}; do
|
|
|
|
$AWS_CMD revoke-security-group-ingress --group-id "${sg_id}" --source-group "${other_sgid}" --protocol all > $LOG
|
|
|
|
done
|
|
|
|
done
|
|
|
|
|
|
|
|
for sg_id in ${sg_ids}; do
|
|
|
|
# EC2 doesn't let us delete the default security group
|
|
|
|
if [[ "${sg_id}" == "${default_sg_id}" ]]; then
|
|
|
|
continue
|
|
|
|
fi
|
|
|
|
|
|
|
|
echo "Deleting security group: ${sg_id}"
|
|
|
|
$AWS_CMD delete-security-group --group-id ${sg_id} > $LOG
|
2015-03-23 20:00:34 +00:00
|
|
|
done
|
|
|
|
|
2015-11-11 04:30:42 +00:00
|
|
|
subnet_ids=$($AWS_CMD describe-subnets \
|
2015-04-23 01:30:09 +00:00
|
|
|
--filters Name=vpc-id,Values=${vpc_id} \
|
2015-06-05 02:03:50 +00:00
|
|
|
Name=tag:KubernetesCluster,Values=${CLUSTER_ID} \
|
2015-03-23 20:00:34 +00:00
|
|
|
--query Subnets[].SubnetId \
|
|
|
|
| tr "\t" "\n")
|
|
|
|
for subnet_id in ${subnet_ids}; do
|
|
|
|
$AWS_CMD delete-subnet --subnet-id ${subnet_id} > $LOG
|
|
|
|
done
|
|
|
|
|
2015-11-11 04:30:42 +00:00
|
|
|
igw_ids=$($AWS_CMD describe-internet-gateways \
|
2015-04-23 01:30:09 +00:00
|
|
|
--filters Name=attachment.vpc-id,Values=${vpc_id} \
|
2015-03-23 20:00:34 +00:00
|
|
|
--query InternetGateways[].InternetGatewayId \
|
|
|
|
| tr "\t" "\n")
|
|
|
|
for igw_id in ${igw_ids}; do
|
|
|
|
$AWS_CMD detach-internet-gateway --internet-gateway-id $igw_id --vpc-id $vpc_id > $LOG
|
|
|
|
$AWS_CMD delete-internet-gateway --internet-gateway-id $igw_id > $LOG
|
|
|
|
done
|
|
|
|
|
2015-11-11 04:30:42 +00:00
|
|
|
route_table_ids=$($AWS_CMD describe-route-tables \
|
2015-03-23 20:00:34 +00:00
|
|
|
--filters Name=vpc-id,Values=$vpc_id \
|
|
|
|
Name=route.destination-cidr-block,Values=0.0.0.0/0 \
|
|
|
|
--query RouteTables[].RouteTableId \
|
|
|
|
| tr "\t" "\n")
|
|
|
|
for route_table_id in ${route_table_ids}; do
|
|
|
|
$AWS_CMD delete-route --route-table-id $route_table_id --destination-cidr-block 0.0.0.0/0 > $LOG
|
|
|
|
done
|
2015-11-11 04:30:42 +00:00
|
|
|
route_table_ids=$($AWS_CMD describe-route-tables \
|
2015-06-12 22:31:03 +00:00
|
|
|
--filters Name=vpc-id,Values=$vpc_id \
|
|
|
|
Name=tag:KubernetesCluster,Values=${CLUSTER_ID} \
|
|
|
|
--query RouteTables[].RouteTableId \
|
|
|
|
| tr "\t" "\n")
|
|
|
|
for route_table_id in ${route_table_ids}; do
|
|
|
|
$AWS_CMD delete-route-table --route-table-id $route_table_id > $LOG
|
|
|
|
done
|
2015-02-11 17:50:47 +00:00
|
|
|
|
|
|
|
$AWS_CMD delete-vpc --vpc-id $vpc_id > $LOG
|
|
|
|
fi
|
2014-09-09 10:17:32 +00:00
|
|
|
}
|
2015-01-07 23:02:35 +00:00
|
|
|
|
2015-03-04 04:18:29 +00:00
|
|
|
# Update a kubernetes cluster with latest source
|
|
|
|
function kube-push {
|
|
|
|
detect-master
|
|
|
|
|
|
|
|
# Make sure we have the tar files staged on Google Storage
|
|
|
|
find-release-tars
|
|
|
|
upload-server-tars
|
|
|
|
|
|
|
|
(
|
|
|
|
echo "#! /bin/bash"
|
|
|
|
echo "mkdir -p /var/cache/kubernetes-install"
|
|
|
|
echo "cd /var/cache/kubernetes-install"
|
2015-03-12 14:36:24 +00:00
|
|
|
echo "readonly SERVER_BINARY_TAR_URL='${SERVER_BINARY_TAR_URL}'"
|
|
|
|
echo "readonly SALT_TAR_URL='${SALT_TAR_URL}'"
|
2015-03-04 04:18:29 +00:00
|
|
|
grep -v "^#" "${KUBE_ROOT}/cluster/aws/templates/common.sh"
|
|
|
|
grep -v "^#" "${KUBE_ROOT}/cluster/aws/templates/download-release.sh"
|
|
|
|
echo "echo Executing configuration"
|
|
|
|
echo "sudo salt '*' mine.update"
|
|
|
|
echo "sudo salt --force-color '*' state.highstate"
|
2015-06-06 17:19:37 +00:00
|
|
|
) | ssh -oStrictHostKeyChecking=no -i "${AWS_SSH_KEY}" ${SSH_USER}@${KUBE_MASTER_IP} sudo bash
|
2015-03-04 04:18:29 +00:00
|
|
|
|
2015-08-22 01:47:31 +00:00
|
|
|
get-kubeconfig-basicauth
|
2015-03-04 04:18:29 +00:00
|
|
|
|
|
|
|
echo
|
|
|
|
echo "Kubernetes cluster is running. The master is running at:"
|
|
|
|
echo
|
|
|
|
echo " https://${KUBE_MASTER_IP}"
|
|
|
|
echo
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-02-11 17:50:47 +00:00
|
|
|
# -----------------------------------------------------------------------------
|
|
|
|
# Cluster specific test helpers used from hack/e2e-test.sh
|
|
|
|
|
|
|
|
# Execute prior to running tests to build a release if required for env.
|
|
|
|
#
|
|
|
|
# Assumed Vars:
|
|
|
|
# KUBE_ROOT
|
|
|
|
function test-build-release {
|
|
|
|
# Make a release
|
|
|
|
"${KUBE_ROOT}/build/release.sh"
|
|
|
|
}
|
|
|
|
|
|
|
|
# Execute prior to running tests to initialize required structure. This is
|
|
|
|
# called from hack/e2e.go only when running -up (it is run after kube-up).
|
|
|
|
#
|
|
|
|
# Assumed vars:
|
|
|
|
# Variables from config.sh
|
|
|
|
function test-setup {
|
2015-06-05 02:03:50 +00:00
|
|
|
VPC_ID=$(get_vpc_id)
|
|
|
|
detect-security-groups
|
|
|
|
|
|
|
|
# Open up port 80 & 8080 so common containers on minions can be reached
|
|
|
|
# TODO(roberthbailey): Remove this once we are no longer relying on hostPorts.
|
2015-11-24 03:05:33 +00:00
|
|
|
authorize-security-group-ingress "${NODE_SG_ID}" "--protocol tcp --port 80 --cidr 0.0.0.0/0"
|
|
|
|
authorize-security-group-ingress "${NODE_SG_ID}" "--protocol tcp --port 8080 --cidr 0.0.0.0/0"
|
2015-06-05 02:03:50 +00:00
|
|
|
|
|
|
|
# Open up the NodePort range
|
|
|
|
# TODO(justinsb): Move to main setup, if we decide whether we want to do this by default.
|
2015-11-24 03:05:33 +00:00
|
|
|
authorize-security-group-ingress "${NODE_SG_ID}" "--protocol all --port 30000-32767 --cidr 0.0.0.0/0"
|
2015-06-05 02:03:50 +00:00
|
|
|
|
2015-02-11 17:50:47 +00:00
|
|
|
echo "test-setup complete"
|
|
|
|
}
|
|
|
|
|
|
|
|
# Execute after running tests to perform any required clean-up. This is called
|
|
|
|
# from hack/e2e.go
|
|
|
|
function test-teardown {
|
2015-06-05 02:03:50 +00:00
|
|
|
# (ingress rules will be deleted along with the security group)
|
2015-02-11 17:50:47 +00:00
|
|
|
echo "Shutting down test cluster."
|
|
|
|
"${KUBE_ROOT}/cluster/kube-down.sh"
|
|
|
|
}
|
|
|
|
|
2015-03-03 17:21:44 +00:00
|
|
|
|
2015-02-11 17:50:47 +00:00
|
|
|
# SSH to a node by name ($1) and run a command ($2).
|
|
|
|
function ssh-to-node {
|
|
|
|
local node="$1"
|
|
|
|
local cmd="$2"
|
2015-03-03 17:21:44 +00:00
|
|
|
|
2015-06-13 04:34:43 +00:00
|
|
|
if [[ "${node}" == "${MASTER_NAME}" ]]; then
|
|
|
|
node=$(get_instanceid_from_name ${MASTER_NAME})
|
|
|
|
if [[ -z "${node-}" ]]; then
|
|
|
|
echo "Could not detect Kubernetes master node. Make sure you've launched a cluster with 'kube-up.sh'"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
2015-03-03 17:21:44 +00:00
|
|
|
local ip=$(get_instance_public_ip ${node})
|
2015-03-25 19:36:52 +00:00
|
|
|
if [[ -z "$ip" ]]; then
|
2015-03-03 17:21:44 +00:00
|
|
|
echo "Could not detect IP for ${node}."
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
2015-02-11 17:50:47 +00:00
|
|
|
for try in $(seq 1 5); do
|
2015-06-06 17:19:37 +00:00
|
|
|
if ssh -oLogLevel=quiet -oStrictHostKeyChecking=no -i "${AWS_SSH_KEY}" ${SSH_USER}@${ip} "${cmd}"; then
|
2015-02-11 17:50:47 +00:00
|
|
|
break
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
|
|
|
# Restart the kube-proxy on a node ($1)
|
|
|
|
function restart-kube-proxy {
|
|
|
|
ssh-to-node "$1" "sudo /etc/init.d/kube-proxy restart"
|
|
|
|
}
|
|
|
|
|
2015-03-04 20:34:02 +00:00
|
|
|
# Restart the kube-apiserver on a node ($1)
|
|
|
|
function restart-apiserver {
|
|
|
|
ssh-to-node "$1" "sudo /etc/init.d/kube-apiserver restart"
|
|
|
|
}
|
|
|
|
|
2015-02-11 17:50:47 +00:00
|
|
|
# Perform preparations required to run e2e tests
|
|
|
|
function prepare-e2e() {
|
|
|
|
# (AWS runs detect-project, I don't think we need to anything)
|
|
|
|
# Note: we can't print anything here, or else the test tools will break with the extra output
|
|
|
|
return
|
|
|
|
}
|
2015-05-13 20:39:22 +00:00
|
|
|
|
|
|
|
function get-tokens() {
|
|
|
|
KUBELET_TOKEN=$(dd if=/dev/urandom bs=128 count=1 2>/dev/null | base64 | tr -d "=+/" | dd bs=32 count=1 2>/dev/null)
|
|
|
|
KUBE_PROXY_TOKEN=$(dd if=/dev/urandom bs=128 count=1 2>/dev/null | base64 | tr -d "=+/" | dd bs=32 count=1 2>/dev/null)
|
|
|
|
}
|
2015-10-21 03:58:24 +00:00
|
|
|
|
|
|
|
# Builds the RUNTIME_CONFIG var from other feature enable options
|
|
|
|
function build-runtime-config() {
|
|
|
|
if [[ "${ENABLE_DEPLOYMENTS}" == "true" ]]; then
|
|
|
|
if [[ -z "${RUNTIME_CONFIG}" ]]; then
|
|
|
|
RUNTIME_CONFIG="extensions/v1beta1/deployments=true"
|
|
|
|
else
|
|
|
|
if echo "${RUNTIME_CONFIG}" | grep -q -v "extensions/v1beta1/deployments=true"; then
|
|
|
|
RUNTIME_CONFIG="${RUNTIME_CONFIG},extensions/v1beta1/deployments=true"
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
if [[ "${ENABLE_DAEMONSETS}" == "true" ]]; then
|
|
|
|
if [[ -z "${RUNTIME_CONFIG}" ]]; then
|
|
|
|
RUNTIME_CONFIG="extensions/v1beta1/daemonsets=true"
|
|
|
|
else
|
|
|
|
if echo "${RUNTIME_CONFIG}" | grep -q -v "extensions/v1beta1/daemonsets=true"; then
|
|
|
|
RUNTIME_CONFIG="${RUNTIME_CONFIG},extensions/v1beta1/daemonsets=true"
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
}
|