2014-09-09 10:17:32 +00:00
#!/bin/bash
2016-06-03 00:25:58 +00:00
# Copyright 2014 The Kubernetes Authors.
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:
2015-11-29 19:38:03 +00:00
# KUBE_USE_EXISTING_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 "
2016-03-09 00:57:31 +00:00
source " ${ KUBE_ROOT } /cluster/lib/util.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 =
2016-01-08 04:31:03 +00:00
# Well known tags
TAG_KEY_MASTER_IP = "kubernetes.io/master-ip"
2016-03-10 11:15:58 +00:00
OS_DISTRIBUTION = ${ KUBE_OS_DISTRIBUTION }
2016-02-25 05:10:33 +00:00
# Defaults: ubuntu -> wily
2016-03-10 11:15:58 +00:00
if [ [ " ${ OS_DISTRIBUTION } " = = "ubuntu" ] ] ; then
OS_DISTRIBUTION = wily
2015-06-25 03:13:17 +00:00
fi
2016-03-10 11:15:58 +00:00
# Loads the distro-specific utils script.
# If the distro is not recommended, prints warnings or exits.
function load_distro_utils ( ) {
case " ${ OS_DISTRIBUTION } " in
jessie)
; ;
wily)
; ;
vivid)
2016-06-18 21:00:48 +00:00
echo "vivid is no longer supported by kube-up; please use jessie instead" >& 2
exit 2
2016-03-10 11:15:58 +00:00
; ;
coreos)
echo "coreos is no longer supported by kube-up; please use jessie instead" >& 2
exit 2
; ;
trusty)
echo "trusty is no longer supported by kube-up; please use jessie or wily instead" >& 2
exit 2
; ;
wheezy)
echo "wheezy is no longer supported by kube-up; please use jessie instead" >& 2
exit 2
2015-05-13 20:39:22 +00:00
; ;
*)
2016-03-10 11:15:58 +00:00
echo " Cannot start cluster using os distro: ${ OS_DISTRIBUTION } " >& 2
echo "The current recommended distro is jessie" >& 2
2015-05-13 20:39:22 +00:00
exit 2
; ;
esac
2016-03-10 11:15:58 +00:00
source " ${ KUBE_ROOT } /cluster/aws/ ${ OS_DISTRIBUTION } /util.sh "
}
load_distro_utils
2015-03-26 19:47:49 +00:00
# This removes the final character in bash (somehow)
2016-05-14 18:08:04 +00:00
re = '[a-zA-Z]'
if [ [ ${ ZONE : -1 } = ~ $re ] ] ; then
AWS_REGION = ${ ZONE %? }
else
AWS_REGION = $ZONE
fi
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
2016-03-22 22:50:16 +00:00
VPC_CIDR_BASE = ${ KUBE_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
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-12-15 23:45:24 +00:00
if [ [ -z " ${ MASTER_INTERNAL_IP - } " ] ] ; then
MASTER_INTERNAL_IP = " ${ SUBNET_CIDR %.* } ${ MASTER_IP_SUFFIX } "
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.
2016-04-02 02:09:20 +00:00
EPHEMERAL_BLOCK_DEVICE_MAPPINGS = ",{\"DeviceName\": \"/dev/sdc\",\"VirtualName\":\"ephemeral0\"},{\"DeviceName\": \"/dev/sdd\",\"VirtualName\":\"ephemeral1\"},{\"DeviceName\": \"/dev/sde\",\"VirtualName\":\"ephemeral2\"},{\"DeviceName\": \"/dev/sdf\",\"VirtualName\":\"ephemeral3\"}"
# Experimental: If the user sets KUBE_AWS_STORAGE to ebs, use ebs storage
# in preference to local instance storage We do this by not mounting any
# instance storage. We could do this better in future (e.g. making instance
# storage available for other purposes)
if [ [ " ${ KUBE_AWS_STORAGE :- } " = = "ebs" ] ] ; then
EPHEMERAL_BLOCK_DEVICE_MAPPINGS = ""
fi
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 \
2016-07-04 13:20:47 +00:00
--filters Name = tag:Name,Values= ${ VPC_NAME } \
2015-03-25 13:23:22 +00:00
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 | \
2016-04-02 10:03:26 +00:00
python -c " import json,sys; lst = [str(lb['LoadBalancerName']) for lb in json.load(sys.stdin)['LoadBalancerDescriptions'] if 'VPCId' in lb and lb['VPCId'] == ' $1 ']; print('\n'.join(lst)) "
2015-03-25 12:36:47 +00:00
}
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"
}
2016-01-08 04:31:03 +00:00
# Finds the master ip, if it is saved (tagged on the master disk)
# Sets KUBE_MASTER_IP
function find-tagged-master-ip {
2016-02-01 22:42:50 +00:00
find-master-pd
2016-01-08 04:31:03 +00:00
if [ [ -n " ${ MASTER_DISK_ID :- } " ] ] ; then
KUBE_MASTER_IP = $( get-tag ${ MASTER_DISK_ID } ${ TAG_KEY_MASTER_IP } )
2014-09-09 10:17:32 +00:00
fi
2016-01-08 04:31:03 +00:00
}
# Gets a tag value from an AWS resource
# usage: get-tag <resource-id> <tag-name>
# outputs: the tag value, or "" if no tag
function get-tag {
$AWS_CMD describe-tags --filters Name = resource-id,Values= ${ 1 } \
Name = key,Values= ${ 2 } \
--query Tags[ ] .Value
}
# Gets an existing master, exiting if not found
2016-02-01 22:42:50 +00:00
# Note that this is called directly by the e2e tests
2016-01-08 04:31:03 +00:00
function detect-master( ) {
find-tagged-master-ip
KUBE_MASTER = ${ MASTER_NAME }
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 ) "
}
2016-03-05 20:50:28 +00:00
# Reads kube-env metadata from master
#
# Assumed vars:
# KUBE_MASTER_IP
# AWS_SSH_KEY
# SSH_USER
function get-master-env( ) {
ssh -oStrictHostKeyChecking= no -i " ${ AWS_SSH_KEY } " ${ SSH_USER } @${ KUBE_MASTER_IP } sudo cat /etc/kubernetes/kube_env.yaml
}
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 }
}
2016-03-16 00:26:46 +00:00
function detect-node-names ( ) {
# If this is called directly, VPC_ID might not be set
# (this is case from cluster/log-dump.sh)
if [ [ -z " ${ VPC_ID :- } " ] ] ; then
VPC_ID = $( get_vpc_id)
fi
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
}
2016-03-16 00:26:46 +00:00
# Called to detect the project on GCE
# Not needed on AWS
function detect-project( ) {
:
}
2015-11-09 07:33:06 +00:00
function detect-nodes ( ) {
2016-03-16 00:26:46 +00:00
detect-node-names
2015-06-13 04:34:43 +00:00
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 ( ) {
2016-03-10 11:15:58 +00:00
case " ${ OS_DISTRIBUTION } " in
2016-02-12 18:25:07 +00:00
wily)
detect-wily-image
; ;
2015-06-06 17:19:37 +00:00
jessie)
detect-jessie-image
; ;
2015-06-06 17:19:37 +00:00
*)
2016-03-10 11:15:58 +00:00
echo " Please specify AWS_IMAGE directly (distro ${ OS_DISTRIBUTION } not recognized) "
2015-06-06 17:19:37 +00:00
exit 2
; ;
esac
}
2015-12-17 12:33:00 +00:00
# Detects the RootDevice to use in the Block Device Mapping (considering the AMI)
#
# Vars set:
# MASTER_BLOCK_DEVICE_MAPPINGS
# NODE_BLOCK_DEVICE_MAPPINGS
#
function detect-root-device {
local master_image = ${ AWS_IMAGE }
local node_image = ${ KUBE_NODE_IMAGE }
ROOT_DEVICE_MASTER = $( $AWS_CMD describe-images --image-ids ${ master_image } --query 'Images[].RootDeviceName' )
if [ [ " ${ master_image } " = = " ${ node_image } " ] ] ; then
ROOT_DEVICE_NODE = ${ ROOT_DEVICE_MASTER }
else
ROOT_DEVICE_NODE = $( $AWS_CMD describe-images --image-ids ${ node_image } --query 'Images[].RootDeviceName' )
fi
2016-04-02 02:09:20 +00:00
MASTER_BLOCK_DEVICE_MAPPINGS = " [{\"DeviceName\":\" ${ ROOT_DEVICE_MASTER } \",\"Ebs\":{\"DeleteOnTermination\":true,\"VolumeSize\": ${ MASTER_ROOT_DISK_SIZE } ,\"VolumeType\":\" ${ MASTER_ROOT_DISK_TYPE } \"}} ${ EPHEMERAL_BLOCK_DEVICE_MAPPINGS } ] "
NODE_BLOCK_DEVICE_MAPPINGS = " [{\"DeviceName\":\" ${ ROOT_DEVICE_NODE } \",\"Ebs\":{\"DeleteOnTermination\":true,\"VolumeSize\": ${ NODE_ROOT_DISK_SIZE } ,\"VolumeType\":\" ${ NODE_ROOT_DISK_TYPE } \"}} ${ EPHEMERAL_BLOCK_DEVICE_MAPPINGS } ] "
2015-12-17 12:33:00 +00:00
}
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
2016-03-05 20:50:28 +00:00
local zone_filter = " Name=availability-zone,Values= ${ ZONE } "
if [ [ " ${ KUBE_USE_EXISTING_MASTER :- } " = = "true" ] ] ; then
# If we're reusing an existing master, it is likely to be in another zone
# If running multizone, your cluster must be uniquely named across zones
zone_filter = ""
fi
2015-11-11 04:30:42 +00:00
MASTER_DISK_ID = ` $AWS_CMD describe-volumes \
2016-03-05 20:50:28 +00:00
--filters ${ zone_filter } \
2015-06-25 20:00:04 +00:00
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
}
2016-01-09 19:08:38 +00:00
# Configures a CloudWatch alarm to reboot the instance on failure
function reboot-on-failure {
local instance_id = $1
echo " Creating Cloudwatch alarm to reboot instance ${ instance_id } on failure "
local aws_owner_id = ` aws ec2 describe-instances --instance-ids ${ instance_id } --query Reservations[ 0] .OwnerId`
if [ [ -z " ${ aws_owner_id } " ] ] ; then
echo " Unable to determinate AWS account id for ${ instance_id } "
exit 1
fi
aws cloudwatch put-metric-alarm \
--alarm-name k8s-${ instance_id } -statuscheckfailure-reboot \
--alarm-description " Reboot ${ instance_id } on status check failure " \
--namespace "AWS/EC2" \
--dimensions Name = InstanceId,Value= ${ instance_id } \
--statistic Minimum \
--metric-name StatusCheckFailed \
--comparison-operator GreaterThanThreshold \
--threshold 0 \
--period 60 \
--evaluation-periods 3 \
--alarm-actions arn:aws:swf:${ AWS_REGION } :${ aws_owner_id } :action/actions/AWS_EC2.InstanceId.Reboot/1.0 > $LOG
# TODO: The IAM role EC2ActionsAccess must have been created
# See e.g. http://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/UsingIAM.html
}
function delete-instance-alarms {
local instance_id = $1
alarm_names = ` aws cloudwatch describe-alarms --alarm-name-prefix k8s-${ instance_id } - --query MetricAlarms[ ] .AlarmName`
for alarm_name in ${ alarm_names } ; do
aws cloudwatch delete-alarms --alarm-names ${ alarm_name } > $LOG
done
}
2016-01-08 04:31:03 +00:00
# Finds the existing master IP, or creates/reuses an Elastic IP
# If MASTER_RESERVED_IP looks like an IP address, we will use it;
# otherwise we will create a new elastic IP
# Sets KUBE_MASTER_IP
function ensure-master-ip {
find-tagged-master-ip
if [ [ -z " ${ KUBE_MASTER_IP :- } " ] ] ; then
# Check if MASTER_RESERVED_IP looks like an IPv4 address
# Note that we used to only allocate an elastic IP when MASTER_RESERVED_IP=auto
# So be careful changing the IPV4 test, to be sure that 'auto' => 'allocate'
if [ [ " ${ MASTER_RESERVED_IP } " = ~ ^[ 0-9] +\. [ 0-9] +\. [ 0-9] +\. [ 0-9] +$ ] ] ; then
KUBE_MASTER_IP = " ${ MASTER_RESERVED_IP } "
else
KUBE_MASTER_IP = ` $AWS_CMD allocate-address --domain vpc --query PublicIp`
echo " Allocated Elastic IP for master: ${ KUBE_MASTER_IP } "
fi
2015-12-15 23:45:24 +00:00
# We can't tag elastic ips. Instead we put the tag on the persistent disk.
# It is a little weird, perhaps, but it sort of makes sense...
# The master mounts the master PD, and whoever mounts the master PD should also
# have the master IP
add-tag ${ MASTER_DISK_ID } ${ TAG_KEY_MASTER_IP } ${ KUBE_MASTER_IP }
2016-01-08 04:31:03 +00:00
fi
}
2016-06-13 14:02:14 +00:00
# Creates a new DHCP option set configured correctly for Kubernetes when DHCP_OPTION_SET_ID is not specified
2015-05-14 16:55:31 +00:00
# Sets DHCP_OPTION_SET_ID
function create-dhcp-option-set ( ) {
2016-06-13 14:02:14 +00:00
if [ [ -z ${ DHCP_OPTION_SET_ID - } ] ] ; then
case " ${ AWS_REGION } " in
us-east-1)
OPTION_SET_DOMAIN = ec2.internal
; ;
2015-05-14 16:55:31 +00:00
2016-06-13 14:02:14 +00:00
*)
OPTION_SET_DOMAIN = " ${ AWS_REGION } .compute.internal "
esac
2015-05-14 16:55:31 +00:00
2016-06-13 14:02:14 +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
2016-06-13 14:02:14 +00:00
add-tag ${ DHCP_OPTION_SET_ID } Name kubernetes-dhcp-option-set
add-tag ${ DHCP_OPTION_SET_ID } KubernetesCluster ${ CLUSTER_ID }
fi
2015-05-14 16:55:31 +00:00
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-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 =
2016-01-18 02:15:05 +00:00
SERVER_BINARY_TAR_HASH =
2014-11-06 22:27:15 +00:00
SALT_TAR_URL =
2016-01-18 02:15:05 +00:00
SALT_TAR_HASH =
2016-02-04 14:36:30 +00:00
BOOTSTRAP_SCRIPT_URL =
BOOTSTRAP_SCRIPT_HASH =
2014-11-06 22:27:15 +00:00
2015-06-09 15:05:25 +00:00
ensure-temp-dir
2016-01-18 02:15:05 +00:00
SERVER_BINARY_TAR_HASH = $( sha1sum-file " ${ SERVER_BINARY_TAR } " )
SALT_TAR_HASH = $( sha1sum-file " ${ SALT_TAR } " )
2016-02-04 14:36:30 +00:00
BOOTSTRAP_SCRIPT_HASH = $( sha1sum-file " ${ BOOTSTRAP_SCRIPT } " )
2016-01-18 02:15:05 +00:00
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 } "
cp -a " ${ SERVER_BINARY_TAR } " ${ local_dir }
cp -a " ${ SALT_TAR } " ${ local_dir }
2016-02-04 14:36:30 +00:00
cp -a " ${ BOOTSTRAP_SCRIPT } " ${ local_dir }
2015-06-04 13:08:04 +00:00
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
2016-02-04 14:36:30 +00:00
local server_binary_path = " ${ staging_path } / ${ SERVER_BINARY_TAR ##*/ } "
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
2016-02-04 14:36:30 +00:00
local bootstrap_script_path = " ${ staging_path } / ${ BOOTSTRAP_SCRIPT ##*/ } "
aws s3api put-object-acl --region ${ s3_bucket_location } --bucket ${ AWS_S3_BUCKET } --key " ${ bootstrap_script_path } " --grant-read 'uri="http://acs.amazonaws.com/groups/global/AllUsers"'
BOOTSTRAP_SCRIPT_URL = " ${ s3_url_base } / ${ AWS_S3_BUCKET } / ${ bootstrap_script_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 } "
2016-02-04 14:36:30 +00:00
echo " BOOTSTRAP_SCRIPT_URL: ${ BOOTSTRAP_SCRIPT_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
2016-09-01 20:02:10 +00:00
# usage: create-iam-profile kubernetes-master-us-west-1a-chom kubernetes-master
2015-03-12 14:59:33 +00:00
function create-iam-profile {
local key = $1
2016-09-01 20:02:10 +00:00
local role = $2
2015-03-12 14:59:33 +00:00
local conf_dir = file://${ KUBE_ROOT } /cluster/aws/templates/iam
echo " Creating IAM role: ${ key } "
2016-09-01 20:02:10 +00:00
aws iam create-role --role-name ${ key } --assume-role-policy-document ${ conf_dir } /${ role } -role.json > $LOG
2015-03-12 14:59:33 +00:00
echo " Creating IAM role-policy: ${ key } "
2016-09-01 20:02:10 +00:00
aws iam put-role-policy --role-name ${ key } --policy-name ${ key } --policy-document ${ conf_dir } /${ role } -policy.json > $LOG
2015-03-12 14:59:33 +00:00
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 {
2016-09-01 20:02:10 +00:00
echo " Creating master IAM profile: ${ IAM_PROFILE_MASTER } "
create-iam-profile ${ IAM_PROFILE_MASTER } kubernetes-master
echo " Creating minion IAM profile: ${ IAM_PROFILE_NODE } "
create-iam-profile ${ IAM_PROFILE_NODE } kubernetes-minion
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
}
2016-01-08 04:31:03 +00:00
# Attaches an elastic IP to the specified instance
function attach-ip-to-instance {
2015-05-06 13:27:17 +00:00
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
}
2016-01-08 04:31:03 +00:00
# Releases an elastic IP
function release-elastic-ip {
local ip_address = $1
echo " Releasing Elastic IP: ${ ip_address } "
elastic_ip_allocation_id = $( $AWS_CMD describe-addresses --public-ips $ip_address --query Addresses[ ] .AllocationId 2> $LOG ) || true
if [ [ -z " ${ elastic_ip_allocation_id } " ] ] ; then
echo "Elastic IP already released"
2015-05-13 07:41:51 +00:00
else
2016-01-08 04:31:03 +00:00
$AWS_CMD release-address --allocation-id ${ elastic_ip_allocation_id } > $LOG
2015-05-06 13:27:17 +00:00
fi
}
2016-03-10 11:37:29 +00:00
# Deletes a security group
# usage: delete_security_group <sgid>
function delete_security_group {
local -r sg_id = ${ 1 }
echo " Deleting security group: ${ sg_id } "
# We retry in case there's a dependent resource - typically an ELB
2016-09-01 20:02:10 +00:00
local n = 0
2016-03-10 11:37:29 +00:00
until [ $n -ge 20 ] ; do
$AWS_CMD delete-security-group --group-id ${ sg_id } > $LOG && return
n = $[ $n +1]
sleep 3
done
echo " Unable to delete security group: ${ sg_id } "
exit 1
}
2016-09-01 20:02:10 +00:00
# Deletes master and minion IAM roles and instance profiles
# usage: delete-iam-instance-profiles
function delete-iam-profiles {
for iam_profile_name in ${ IAM_PROFILE_MASTER } ${ IAM_PROFILE_NODE } ; do
echo " Removing role from instance profile: ${ iam_profile_name } "
conceal-no-such-entity-response aws iam remove-role-from-instance-profile --instance-profile-name " ${ iam_profile_name } " --role-name " ${ iam_profile_name } "
echo " Deleting IAM Instance-Profile: ${ iam_profile_name } "
conceal-no-such-entity-response aws iam delete-instance-profile --instance-profile-name " ${ iam_profile_name } "
echo " Delete IAM role policy: ${ iam_profile_name } "
conceal-no-such-entity-response aws iam delete-role-policy --role-name " ${ iam_profile_name } " --policy-name " ${ iam_profile_name } "
echo " Deleting IAM Role: ${ iam_profile_name } "
conceal-no-such-entity-response aws iam delete-role --role-name " ${ iam_profile_name } "
done
}
# Detects NoSuchEntity response from AWS cli stderr output and conceals error
# Otherwise the error is treated as fatal
# usage: conceal-no-such-entity-response ...args
function conceal-no-such-entity-response {
# in plain english: redirect stderr to stdout, and stdout to the log file
local -r errMsg = $( $@ 2>& 1 > $LOG )
if [ [ " $errMsg " = = "" ] ] ; then
return
fi
echo $errMsg
if [ [ " $errMsg " = ~ " (NoSuchEntity) " ] ] ; then
echo " -> no such entity response detected. will assume operation is not necessary due to prior incomplete teardown"
return
fi
echo "Error message is fatal. Will exit"
exit 1
}
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
2016-07-04 13:20:47 +00:00
add-tag $VPC_ID Name ${ VPC_NAME }
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-12-15 23:45:24 +00:00
if [ ! $SUBNET_CIDR = $EXISTING_CIDR ] ; then
MASTER_INTERNAL_IP = " ${ EXISTING_CIDR %.* } ${ MASTER_IP_SUFFIX } "
echo " Assuming MASTER_INTERNAL_IP= ${ MASTER_INTERNAL_IP } "
fi
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 {
2016-03-10 11:15:58 +00:00
echo " Starting cluster using os distro: ${ OS_DISTRIBUTION } " >& 2
2015-11-25 22:20:22 +00:00
get-tokens
detect-image
detect-minion-image
2015-12-17 12:33:00 +00:00
detect-root-device
2015-11-25 22:20:22 +00:00
find-release-tars
ensure-temp-dir
2016-02-04 14:36:30 +00:00
create-bootstrap-script
2015-11-25 22:20:22 +00:00
upload-server-tars
ensure-iam-profiles
load-or-gen-kube-basicauth
2016-02-04 14:36:30 +00:00
load-or-gen-kube-bearertoken
2015-11-25 22:20:22 +00:00
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
# SSH is open to the world
2016-06-08 18:33:15 +00:00
authorize-security-group-ingress " ${ MASTER_SG_ID } " " --protocol tcp --port 22 --cidr ${ SSH_CIDR } "
authorize-security-group-ingress " ${ NODE_SG_ID } " " --protocol tcp --port 22 --cidr ${ SSH_CIDR } "
2015-06-05 02:03:50 +00:00
# HTTPS to the master is allowed (for API access)
2016-06-08 18:33:15 +00:00
authorize-security-group-ingress " ${ MASTER_SG_ID } " " --protocol tcp --port 443 --cidr ${ HTTP_API_CIDR } "
2015-06-05 02:03:50 +00:00
2015-11-29 19:38:03 +00:00
# KUBE_USE_EXISTING_MASTER is used to add minions to an existing master
if [ [ " ${ KUBE_USE_EXISTING_MASTER :- } " = = "true" ] ] ; then
2015-11-03 16:01:41 +00:00
detect-master
2016-03-05 20:50:28 +00:00
parse-master-env
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 16:01:41 +00:00
else
# Create the master
start-master
2015-11-03 15:10:51 +00:00
2016-02-21 16:44:29 +00:00
# Build ~/.kube/config
build-config
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
fi
2015-11-03 15:10:51 +00:00
# Check the cluster is OK
check-cluster
}
2016-02-04 14:36:30 +00:00
# Builds the bootstrap script and saves it to a local temp file
# Sets BOOTSTRAP_SCRIPT to the path of the script
function create-bootstrap-script( ) {
ensure-temp-dir
BOOTSTRAP_SCRIPT = " ${ KUBE_TEMP } /bootstrap-script "
(
# Include the default functions from the GCE configure-vm script
sed '/^#+AWS_OVERRIDES_HERE/,$d' " ${ KUBE_ROOT } /cluster/gce/configure-vm.sh "
# Include the AWS override functions
cat " ${ KUBE_ROOT } /cluster/aws/templates/configure-vm-aws.sh "
cat " ${ KUBE_ROOT } /cluster/aws/templates/format-disks.sh "
# Include the GCE configure-vm directly-executed code
sed -e '1,/^#+AWS_OVERRIDES_HERE/d' " ${ KUBE_ROOT } /cluster/gce/configure-vm.sh "
) > " ${ BOOTSTRAP_SCRIPT } "
}
2015-11-03 15:10:51 +00:00
# Starts the master node
function start-master( ) {
2016-01-24 15:37:41 +00:00
# Ensure RUNTIME_CONFIG is populated
build-runtime-config
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
2016-01-08 04:31:03 +00:00
# Get or create master elastic IP
ensure-master-ip
2016-02-04 14:36:30 +00:00
# We have to make sure that the cert is valid for API_SERVERS
# i.e. we likely have to pass ELB name / elastic IP in future
2016-02-04 21:16:04 +00:00
create-certs " ${ KUBE_MASTER_IP } " " ${ MASTER_INTERNAL_IP } "
2016-02-04 14:36:30 +00:00
# This key is no longer needed, and this enables us to get under the 16KB size limit
KUBECFG_CERT_BASE64 = ""
KUBECFG_KEY_BASE64 = ""
2015-07-03 04:30:04 +00:00
2016-01-18 02:17:14 +00:00
write-master-env
2015-07-03 04:30:04 +00:00
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"
2016-01-18 02:17:14 +00:00
2016-02-04 14:36:30 +00:00
echo "cat > kube_env.yaml << __EOF_MASTER_KUBE_ENV_YAML"
2016-01-18 02:17:14 +00:00
cat ${ KUBE_TEMP } /master-kube-env.yaml
2016-02-28 01:43:51 +00:00
echo "AUTO_UPGRADE: 'true'"
2016-01-18 02:17:14 +00:00
# TODO: get rid of these exceptions / harmonize with common or GCE
echo " DOCKER_STORAGE: $( yaml-quote ${ DOCKER_STORAGE :- } ) "
2016-02-04 14:36:30 +00:00
echo " API_SERVERS: $( yaml-quote ${ MASTER_INTERNAL_IP :- } ) "
2016-01-18 02:17:14 +00:00
echo "__EOF_MASTER_KUBE_ENV_YAML"
2016-02-04 14:36:30 +00:00
echo ""
echo " wget -O bootstrap ${ BOOTSTRAP_SCRIPT_URL } "
echo "chmod +x bootstrap"
2016-02-12 15:52:59 +00:00
echo "mkdir -p /etc/kubernetes"
echo "mv kube_env.yaml /etc/kubernetes"
echo "mv bootstrap /etc/kubernetes/"
echo "cat > /etc/rc.local << EOF_RC_LOCAL"
echo "#!/bin/sh -e"
# We want to be sure that we don't pass an argument to bootstrap
echo "/etc/kubernetes/bootstrap"
echo "exit 0"
echo "EOF_RC_LOCAL"
echo "/etc/kubernetes/bootstrap"
2015-11-09 06:14:51 +00:00
) > " ${ KUBE_TEMP } /master-user-data "
2016-02-04 14:36:30 +00:00
# Compress the data to fit under the 16KB limit (cloud-init accepts compressed data)
gzip " ${ KUBE_TEMP } /master-user-data "
2014-11-06 22:27:15 +00:00
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 } " \
2016-02-04 14:36:30 +00:00
--user-data fileb://${ KUBE_TEMP } /master-user-data.gz \
2015-11-11 04:30:42 +00:00
--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 }
2016-01-08 04:31:03 +00:00
echo -e " ${ color_green } [master running] ${ color_norm } "
2015-12-11 18:35:00 +00:00
2016-01-08 04:31:03 +00:00
attach-ip-to-instance ${ KUBE_MASTER_IP } ${ master_id }
2015-03-26 17:26:23 +00:00
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-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( ) {
2016-01-24 15:37:41 +00:00
# Minions don't currently use runtime config, but call it anyway for sanity
build-runtime-config
2015-06-13 04:34:43 +00:00
echo "Creating minion configuration"
2016-02-04 14:36:30 +00:00
write-node-env
(
# 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"
echo "cat > kube_env.yaml << __EOF_KUBE_ENV_YAML"
cat ${ KUBE_TEMP } /node-kube-env.yaml
2016-02-28 01:43:51 +00:00
echo "AUTO_UPGRADE: 'true'"
2016-02-04 14:36:30 +00:00
# TODO: get rid of these exceptions / harmonize with common or GCE
echo " DOCKER_STORAGE: $( yaml-quote ${ DOCKER_STORAGE :- } ) "
echo " API_SERVERS: $( yaml-quote ${ MASTER_INTERNAL_IP :- } ) "
echo "__EOF_KUBE_ENV_YAML"
echo ""
echo " wget -O bootstrap ${ BOOTSTRAP_SCRIPT_URL } "
echo "chmod +x bootstrap"
2016-02-12 15:52:59 +00:00
echo "mkdir -p /etc/kubernetes"
echo "mv kube_env.yaml /etc/kubernetes"
echo "mv bootstrap /etc/kubernetes/"
echo "cat > /etc/rc.local << EOF_RC_LOCAL"
echo "#!/bin/sh -e"
# We want to be sure that we don't pass an argument to bootstrap
echo "/etc/kubernetes/bootstrap"
echo "exit 0"
echo "EOF_RC_LOCAL"
echo "/etc/kubernetes/bootstrap"
2016-02-04 14:36:30 +00:00
) > " ${ KUBE_TEMP } /node-user-data "
# Compress the data to fit under the 16KB limit (cloud-init accepts compressed data)
gzip " ${ KUBE_TEMP } /node-user-data "
2015-06-13 04:34:43 +00:00
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
2016-02-21 16:45:09 +00:00
local spot_price_option
if [ [ -n " ${ NODE_SPOT_PRICE :- } " ] ] ; then
spot_price_option = " --spot-price ${ NODE_SPOT_PRICE } "
else
spot_price_option = ""
fi
2015-06-13 04:34:43 +00:00
${ 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 } \
2016-02-21 16:45:09 +00:00
${ spot_price_option } \
2015-11-24 03:01:03 +00:00
--block-device-mappings " ${ NODE_BLOCK_DEVICE_MAPPINGS } " \
2016-02-04 14:36:30 +00:00
--user-data " fileb:// ${ KUBE_TEMP } /node-user-data.gz "
2015-06-13 04:34:43 +00:00
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
2016-02-24 02:48:25 +00:00
local attempt = 0
local max_attempts = 30
# Spot instances are slower to launch
if [ [ -n " ${ NODE_SPOT_PRICE :- } " ] ] ; then
max_attempts = 90
fi
2015-06-13 04:34:43 +00:00
while true; do
2016-03-16 00:26:46 +00:00
detect-node-names > $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
2016-02-24 02:48:25 +00:00
if ( ( attempt > max_attempts ) ) ; then
2015-06-13 04:34:43 +00:00
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
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
2016-02-04 21:16:44 +00:00
# The master must be running and set in KUBE_MASTER_IP
2015-11-03 15:10:51 +00:00
function build-config( ) {
2016-02-04 21:16:44 +00:00
export KUBE_CERT = " ${ CERT_DIR } /pki/issued/kubecfg.crt "
export KUBE_KEY = " ${ CERT_DIR } /pki/private/kubecfg.key "
export CA_CERT = " ${ CERT_DIR } /pki/ca.crt "
2016-04-28 04:05:37 +00:00
export CONTEXT = " ${ CONFIG_CONTEXT } "
2014-11-06 22:27:15 +00:00
(
2016-02-04 21:16:44 +00:00
umask 077
2016-06-14 01:37:07 +00:00
# Update the user's kubeconfig to include credentials for this apiserver.
2016-02-04 21:16:44 +00:00
create-kubeconfig
2016-06-14 01:37:07 +00:00
2016-06-20 23:10:47 +00:00
create-kubeconfig-for-federation
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
2016-05-10 13:06:45 +00:00
if ( ( attempt > 20 ) ) ; then
2015-03-03 17:24:56 +00:00
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
2016-01-09 19:08:38 +00:00
if [ [ -z " ${ KUBE_MASTER_ID - } " ] ] ; then
KUBE_MASTER_ID = $( get_instanceid_from_name ${ MASTER_NAME } )
fi
if [ [ -n " ${ KUBE_MASTER_ID - } " ] ] ; then
delete-instance-alarms ${ KUBE_MASTER_ID }
fi
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
2016-08-17 21:44:54 +00:00
if [ [ -n $( ${ AWS_ASG_CMD } describe-launch-configurations --launch-configuration-names ${ ASG_NAME } --query LaunchConfigurations[ ] .LaunchConfigurationName) ] ] ; then
echo " Warning: default auto-scaling launch configuration ${ ASG_NAME } still exists, attempting to delete "
echo " (This may happen if kube-up leaves just the launch configuration but no auto-scaling group.)"
${ AWS_ASG_CMD } delete-launch-configuration --launch-configuration-name ${ ASG_NAME } || true
fi
2015-03-25 13:23:22 +00:00
2016-01-08 04:31:03 +00:00
find-master-pd
find-tagged-master-ip
if [ [ -n " ${ KUBE_MASTER_IP :- } " ] ] ; then
release-elastic-ip ${ KUBE_MASTER_IP }
fi
if [ [ -n " ${ MASTER_DISK_ID :- } " ] ] ; then
echo " Deleting volume ${ MASTER_DISK_ID } "
$AWS_CMD delete-volume --volume-id ${ MASTER_DISK_ID } > $LOG
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
2016-03-10 11:37:29 +00:00
delete_security_group ${ sg_id }
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
2016-01-08 04:31:03 +00:00
echo " Deleting VPC: ${ vpc_id } "
2015-02-11 17:50:47 +00:00
$AWS_CMD delete-vpc --vpc-id $vpc_id > $LOG
2016-06-16 03:53:57 +00:00
else
echo "" >& 2
echo -e " ${ color_red } Cluster NOT deleted! ${ color_norm } " >& 2
echo "" >& 2
echo " No VPC was found with tag KubernetesCluster= ${ CLUSTER_ID } " >& 2
echo "" >& 2
echo "If you are trying to delete a cluster in a shared VPC," >& 2
echo "please consider using one of the methods in the kube-deploy repo." >& 2
echo "See: https://github.com/kubernetes/kube-deploy/blob/master/docs/delete_cluster.md" >& 2
2016-08-10 17:31:48 +00:00
echo "" >& 2
echo "Note: You may be seeing this message may be because the cluster was already deleted, or" >& 2
echo " has a name other than ' ${ CLUSTER_ID } '. " >& 2
2015-02-11 17:50:47 +00:00
fi
2016-09-01 20:02:10 +00:00
echo "Deleting IAM Instance profiles"
delete-iam-profiles
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
2016-02-04 14:36:30 +00:00
create-bootstrap-script
2015-03-04 04:18:29 +00:00
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
# -----------------------------------------------------------------------------
2016-02-16 22:54:50 +00:00
# Cluster specific test helpers used from hack/e2e.go
2015-02-11 17:50:47 +00:00
# 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
2016-02-18 00:49:07 +00:00
# called from hack/e2e.go only when running -up.
2015-02-11 17:50:47 +00:00
#
# Assumed vars:
# Variables from config.sh
function test-setup {
2016-06-24 17:44:35 +00:00
" ${ KUBE_ROOT } /cluster/kube-up.sh "
2016-02-18 00:49:07 +00:00
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
2016-03-16 00:26:46 +00:00
# Gets the hostname (or IP) that we should SSH to for the given nodename
# For the master, we use the nodename, for the nodes we use their instanceids
function get_ssh_hostname {
2015-02-11 17:50:47 +00:00
local node = " $1 "
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
2016-03-16 00:26:46 +00:00
echo "Could not detect Kubernetes master node. Make sure you've launched a cluster with 'kube-up.sh'" 1>& 2
2015-06-13 04:34:43 +00:00
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
2016-03-16 00:26:46 +00:00
echo " Could not detect IP for ${ node } . " 1>& 2
2015-03-03 17:21:44 +00:00
exit 1
fi
2016-03-16 00:26:46 +00:00
echo ${ ip }
}
# SSH to a node by name ($1) and run a command ($2).
function ssh-to-node {
local node = " $1 "
local cmd = " $2 "
local ip = $( get_ssh_hostname ${ node } )
2015-03-03 17:21:44 +00:00
2016-06-03 17:42:38 +00:00
for try in { 1..5} ; do
2016-03-07 21:29:04 +00:00
if ssh -oLogLevel= quiet -oConnectTimeout= 30 -oStrictHostKeyChecking= no -i " ${ AWS_SSH_KEY } " ${ SSH_USER } @${ ip } "echo test > /dev/null" ; then
2015-02-11 17:50:47 +00:00
break
fi
2016-03-07 21:29:04 +00:00
sleep 5
2015-02-11 17:50:47 +00:00
done
2016-03-07 21:29:04 +00:00
ssh -oLogLevel= quiet -oConnectTimeout= 30 -oStrictHostKeyChecking= no -i " ${ AWS_SSH_KEY } " ${ SSH_USER } @${ ip } " ${ cmd } "
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)
}