diff --git a/cluster/kube-down-azure.sh b/cluster/kube-down-azure.sh new file mode 100755 index 00000000000..a9441945487 --- /dev/null +++ b/cluster/kube-down-azure.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +SCRIPT_DIR=$(CDPATH="" cd $(dirname $0); pwd) +source $SCRIPT_DIR/../release/config-azure.sh +source $SCRIPT_DIR/util.sh + + +echo "Bringing down cluster" +azure vm delete $MASTER_NAME -b -q +for (( i=0; i<${#MINION_NAMES[@]}; i++)); do + azure vm delete ${MINION_NAMES[$i]} -b -q +done diff --git a/cluster/kube-up-azure.sh b/cluster/kube-up-azure.sh new file mode 100755 index 00000000000..31c4c00593b --- /dev/null +++ b/cluster/kube-up-azure.sh @@ -0,0 +1,145 @@ +#!/bin/bash + +# Copyright 2014 Google Inc. All rights reserved. +# +# 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. + +# Bring up a Kubernetes cluster. +# +# If the full release name (gs:///) is passed in then we take +# that directly. If not then we assume we are doing development stuff and take +# the defaults in the release config. + +# exit on any error +set -eu +set -o pipefail +SCRIPT_DIR=$(CDPATH="" cd $(dirname $0); pwd) + +source $SCRIPT_DIR/../release/config-azure.sh +source $SCRIPT_DIR/util.sh + +KUBE_TEMP=$(mktemp -d -t kubernetes.XXXXXX) +trap "rm -rf ${KUBE_TEMP}" EXIT + +get-password +echo "Using password: $user:$passwd" +python $SCRIPT_DIR/../third_party/htpasswd/htpasswd.py -b -c ${KUBE_TEMP}/htpasswd $user $passwd +HTPASSWD=$(cat ${KUBE_TEMP}/htpasswd) + +# Build up start up script for master +( + echo "#!/bin/bash" + echo "MASTER_NAME=${MASTER_NAME}" + echo "MASTER_RELEASE_TAR=${FULL_URL}" + echo "MASTER_HTPASSWD='${HTPASSWD}'" + grep -v "^#" $SCRIPT_DIR/templates/download-release-azure.sh + grep -v "^#" $SCRIPT_DIR/templates/salt-master.sh +) > ${KUBE_TEMP}/master-start.sh + +echo "Starting VMs" + +if [ ! -f $AZ_SSH_KEY ]; then + ssh-keygen -f $AZ_SSH_KEY -N '' +fi + +if [ ! -f $AZ_SSH_CERT ]; then + openssl req -new -key $AZ_SSH_KEY -out ${KUBE_TEMP}/temp.csr \ + -subj "/C=US/ST=WA/L=Redmond/O=Azure-CLI/CN=Azure" + openssl req -x509 -key $AZ_SSH_KEY -in ${KUBE_TEMP}/temp.csr -out $AZ_SSH_CERT -days 1095 + rm ${KUBE_TEMP}/temp.csr +fi + +if [ -z "$(azure network vnet show $AZ_VNET 2>/dev/null | grep data)" ]; then + #azure network vnet create with $AZ_SUBNET + #FIXME not working + echo error create vnet $AZ_VNET with subnet $AZ_SUBNET + exit 1 +fi + + +azure vm create \ + -w $AZ_VNET \ + -n $MASTER_NAME \ + -l "$AZ_LOCATION" \ + -t $AZ_SSH_CERT \ + -e 22000 -P \ + -d ${KUBE_TEMP}/master-start.sh \ + -b $AZ_SUBNET \ + $AZ_CS $AZ_IMAGE $USER + + +ssh_ports=($(eval echo "2200{1..$NUM_MINIONS}")) + +for (( i=0; i<${#MINION_NAMES[@]}; i++)); do + ( + echo "#!/bin/bash" + echo "MASTER_NAME=${MASTER_NAME}" + echo "MINION_IP_RANGE=${MINION_IP_RANGES[$i]}" + grep -v "^#" $SCRIPT_DIR/templates/salt-minion-azure.sh + ) > ${KUBE_TEMP}/minion-start-${i}.sh + + azure vm create \ + -c -w $AZ_VNET \ + -n ${MINION_NAMES[$i]} \ + -l "$AZ_LOCATION" \ + -t $AZ_SSH_CERT \ + -e ${ssh_ports[$i]} -P \ + -d ${KUBE_TEMP}/minion-start-${i}.sh \ + -b $AZ_SUBNET \ + $AZ_CS $AZ_IMAGE $USER + +done + +azure vm endpoint create $MASTER_NAME 443 + +echo " https://${user}:${passwd}@$AZ_CS.cloudapp.net" + +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 ${user}:${passwd} --max-time 5 \ + --fail --output /dev/null --silent https://$AZ_CS.cloudapp.net/api/v1beta1/pods); do + printf "." + sleep 2 +done + +# Basic sanity checking +for (( i=0; i<${#MINION_NAMES[@]}; i++)); do + # Make sure docker is installed + ssh -i $AZ_SSH_KEY -p ${ssh_ports[$i]} $AZ_CS.cloudapp.net which docker > /dev/null + if [ "$?" != "0" ]; then + echo "Docker failed to install on ${MINION_NAMES[$i]} your cluster is unlikely to work correctly" + echo "Please run ./cluster/kube-down.sh and re-create the cluster. (sorry!)" + exit 1 + fi + + # Make sure the kubelet is running + ssh -i $AZ_SSH_KEY -p ${ssh_ports[$i]} $AZ_CS.cloudapp.net /etc/init.d/kubelet status + if [ "$?" != "0" ]; then + echo "Kubelet failed to install on ${MINION_NAMES[$i]} your cluster is unlikely to work correctly" + echo "Please run ./cluster/kube-down.sh and re-create the cluster. (sorry!)" + exit 1 + fi +done + +echo +echo "Kubernetes cluster is running. Access the master at:" +echo +echo " https://${user}:${passwd}@$AZ_CS.cloudapp.net" +echo +echo "Security note: The server above uses a self signed certificate. This is" +echo " subject to \"Man in the middle\" type attacks." diff --git a/cluster/templates/download-release-azure.sh b/cluster/templates/download-release-azure.sh new file mode 100644 index 00000000000..0eed27faf65 --- /dev/null +++ b/cluster/templates/download-release-azure.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +# Copyright 2014 Google Inc. All rights reserved. +# +# 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. + +# Download and install release + +# This script assumes that the environment variable MASTER_RELEASE_TAR contains +# the release tar to download and unpack. It is meant to be pushed to the +# master and run. + +echo "Downloading release ($MASTER_RELEASE_TAR)" +wget $MASTER_RELEASE_TAR + +echo "Unpacking release" +rm -rf master-release || false +tar xzf master-release.tgz + +echo "Running release install script" +sudo master-release/src/scripts/master-release-install.sh diff --git a/cluster/templates/salt-master-azure.sh b/cluster/templates/salt-master-azure.sh new file mode 100644 index 00000000000..703b41afe05 --- /dev/null +++ b/cluster/templates/salt-master-azure.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +# Copyright 2014 Google Inc. All rights reserved. +# +# 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. + +# Prepopulate the name of the Master +mkdir -p /etc/salt/minion.d +echo "master: $MASTER_NAME" > /etc/salt/minion.d/master.conf + +cat </etc/salt/minion.d/grains.conf +grains: + roles: + - kubernetes-master +EOF + +# Auto accept all keys from minions that try to join +mkdir -p /etc/salt/master.d +cat </etc/salt/master.d/auto-accept.conf +auto_accept: True +EOF + +cat </etc/salt/master.d/reactor.conf +# React to new minions starting by running highstate on them. +reactor: + - 'salt/minion/*/start': + - /srv/reactor/start.sls +EOF + +mkdir -p /srv/salt/nginx +echo $MASTER_HTPASSWD > /srv/salt/nginx/htpasswd + +# Install Salt +# +# We specify -X to avoid a race condition that can cause minion failure to +# install. See https://github.com/saltstack/salt-bootstrap/issues/270 +# +# -M installs the master +curl -L http://bootstrap.saltstack.com | sh -s -- -M -X + +echo $MASTER_HTPASSWD > /srv/salt/nginx/htpasswd diff --git a/cluster/templates/salt-minion-azure.sh b/cluster/templates/salt-minion-azure.sh new file mode 100644 index 00000000000..428dbe30eea --- /dev/null +++ b/cluster/templates/salt-minion-azure.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +# Copyright 2014 Google Inc. All rights reserved. +# +# 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. + +# Prepopulate the name of the Master +mkdir -p /etc/salt/minion.d +echo "master: $MASTER_NAME" > /etc/salt/minion.d/master.conf + +# Turn on debugging for salt-minion +# echo "DAEMON_ARGS=\"\$DAEMON_ARGS --log-file-level=debug\"" > /etc/default/salt-minion + +# Our minions will have a pool role to distinguish them from the master. +cat </etc/salt/minion.d/grains.conf +grains: + roles: + - kubernetes-pool + cbr-cidr: $MINION_IP_RANGE +EOF + +# Install Salt +# +# We specify -X to avoid a race condition that can cause minion failure to +# install. See https://github.com/saltstack/salt-bootstrap/issues/270 +curl -L http://bootstrap.saltstack.com | sh -s -- -X diff --git a/hack/dev-build-and-up-azure.sh b/hack/dev-build-and-up-azure.sh new file mode 100755 index 00000000000..09b40927d86 --- /dev/null +++ b/hack/dev-build-and-up-azure.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# Copyright 2014 Google Inc. All rights reserved. +# +# 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. + +# This script will build a dev release and bring up a new cluster with that +# release. + +# First build a release +$(dirname $0)/../release/release-azure.sh + +# Now bring a new cluster up with that release. +$(dirname $0)/../cluster/kube-up-azure.sh diff --git a/release/config-azure.sh b/release/config-azure.sh new file mode 100644 index 00000000000..7dda68bab53 --- /dev/null +++ b/release/config-azure.sh @@ -0,0 +1,35 @@ + +AZ_LOCATION='West US' +AZ_SSH_KEY=$HOME/.ssh/azure +AZ_SSH_CERT=$HOME/.ssh/azure.pem +AZ_IMAGE=b39f27a8b8c64d52b05eac6a62ebad85__Ubuntu-14_04-LTS-amd64-server-20140618.1-en-us-30GB +AZ_SUBNET=Subnet-1 +TAG=testing + +if [ -z "$(which azure)" ]; then + echo "Couldn't find azure in PATH" + exit 1 +fi + +if [ -z "$(azure account list | grep true)" ]; then + echo "Default azure account not set" + exit 1 +fi + +account=$(azure account list | grep true | awk '{ print $2 }') + +if which md5 > /dev/null 2>&1; then + hsh=$(md5 -q -s $account) +else + hsh=$(echo -n "$account" | md5sum) +fi +hsh=${hsh:0:7} + +STG_ACCOUNT=kube$hsh + +AZ_VNET=kube-$hsh +AZ_CS=kube-$hsh + +CONTAINER=kube-$TAG + +FULL_URL="https://${STG_ACCOUNT}.blob.core.windows.net/$CONTAINER/master-release.tgz" diff --git a/release/release-azure.sh b/release/release-azure.sh new file mode 100755 index 00000000000..ef41ac0c46b --- /dev/null +++ b/release/release-azure.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +set -eu +set -o pipefail +IFS=$'\n\t' +SCRIPT_DIR=$(CDPATH="" cd $(dirname $0); pwd) + +function json_val () { + python -c 'import json,sys;obj=json.load(sys.stdin);print obj'$1''; +} + +source $SCRIPT_DIR/config-azure.sh +source $SCRIPT_DIR/../cluster/${KUBE_CONFIG_FILE-"config-default.sh"} + +$SCRIPT_DIR/build-release.sh $INSTANCE_PREFIX + +if [ -z "$(azure storage account show $STG_ACCOUNT 2>/dev/null | grep data)" ]; then + azure storage account create -l "$AZ_LOCATION" $STG_ACCOUNT +fi + +stg_key=$(azure storage account keys list $STG_ACCOUNT --json | json_val '["primaryKey"]') + +if [ -z "$(azure storage container show -a $STG_ACCOUNT -k "$stg_key" $CONTAINER 2>/dev/null | grep data)" ]; then + azure storage container create \ + -a $STG_ACCOUNT \ + -k "$stg_key" \ + -p Blob \ + $CONTAINER +fi + +if [ -n "$(azure storage blob show \ + -a $STG_ACCOUNT \ + -k "$stg_key" \ + $CONTAINER \ + master-release.tgz 2>/dev/null | grep data)" ]; then + azure storage blob delete \ + -a $STG_ACCOUNT \ + -k "$stg_key" \ + $CONTAINER \ + master-release.tgz +fi + +azure storage blob upload \ + -a $STG_ACCOUNT \ + -k "$stg_key" \ + $SCRIPT_DIR/../output/release/master-release.tgz \ + $CONTAINER \ + master-release.tgz