2015-01-30 05:15:34 +00:00
#!/bin/bash
2015-01-30 05:22:17 +00:00
2016-06-03 00:25:58 +00:00
# Copyright 2014 The Kubernetes Authors.
2015-01-30 05:22:17 +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
2015-01-30 05:15:34 +00:00
#
2015-01-30 05:22:17 +00:00
# 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.
2016-10-11 23:22:02 +00:00
# LIMITATIONS
# 1. Exit code is probably not always correct.
# 2. There are no unittests.
# 3. Will not work if the total length of paths to addons is greater than
# bash can handle. Probably it is not a problem: ARG_MAX=2097152 on GCE.
# cosmetic improvements to be done
# 1. Improve the log function; add timestamp, file name, etc.
# 2. Logging doesn't work from files that print things out.
# 3. Kubectl prints the output to stderr (the output should be captured and then
# logged)
2015-06-10 21:47:14 +00:00
KUBECTL = ${ KUBECTL_BIN :- /usr/local/bin/kubectl }
2016-08-11 01:08:01 +00:00
KUBECTL_OPTS = ${ KUBECTL_OPTS :- }
2015-03-11 20:42:41 +00:00
2016-06-21 14:42:53 +00:00
ADDON_CHECK_INTERVAL_SEC = ${ TEST_ADDON_CHECK_INTERVAL_SEC :- 60 }
2016-10-11 23:22:02 +00:00
ADDON_PATH = ${ ADDON_PATH :- /etc/kubernetes/addons }
2015-06-15 14:31:17 +00:00
2015-06-25 04:55:40 +00:00
SYSTEM_NAMESPACE = kube-system
2017-02-25 00:42:16 +00:00
# Addons could use this label with two modes:
# - ADDON_MANAGER_LABEL=Reconcile
# - ADDON_MANAGER_LABEL=EnsureExists
ADDON_MANAGER_LABEL = "addonmanager.kubernetes.io/mode"
# This label is deprecated (only for Addon Manager). In future release
# addon-manager may not respect it anymore. Addons with
# CLUSTER_SERVICE_LABEL=true and without ADDON_MANAGER_LABEL=EnsureExists
# will be reconciled for now.
CLUSTER_SERVICE_LABEL = "kubernetes.io/cluster-service"
2017-11-10 08:10:53 +00:00
# Whether only one addon manager should be running in a multi-master setup.
# Disabling this flag will force all addon managers to assume they are the
# leaders.
ADDON_MANAGER_LEADER_ELECTION = ${ ADDON_MANAGER_LEADER_ELECTION :- true }
2016-10-11 23:22:02 +00:00
# Remember that you can't log from functions that print some output (because
# logs are also printed on stdout).
# $1 level
# $2 message
function log( ) {
# manage log levels manually here
# add the timestamp if you find it useful
case $1 in
DB3 )
# echo "$1: $2"
; ;
DB2 )
# echo "$1: $2"
; ;
DBG )
# echo "$1: $2"
; ;
INFO )
echo " $1 : $2 "
; ;
WRN )
echo " $1 : $2 "
; ;
ERR )
echo " $1 : $2 "
; ;
* )
echo " INVALID_LOG_LEVEL $1 : $2 "
; ;
esac
}
2015-03-13 22:34:00 +00:00
# $1 filename of addon to start.
2015-04-02 21:07:23 +00:00
# $2 count of tries to start the addon.
# $3 delay in seconds between two consecutive tries
2015-06-25 04:55:40 +00:00
# $4 namespace
2015-04-02 21:07:23 +00:00
function start_addon( ) {
2015-03-13 22:34:00 +00:00
local -r addon_filename = $1 ;
local -r tries = $2 ;
local -r delay = $3 ;
2015-06-25 04:55:40 +00:00
local -r namespace = $4
2015-03-13 22:34:00 +00:00
2016-10-11 23:22:02 +00:00
create_resource_from_string " $( cat ${ addon_filename } ) " " ${ tries } " " ${ delay } " " ${ addon_filename } " " ${ namespace } "
2015-03-13 22:34:00 +00:00
}
# $1 string with json or yaml.
# $2 count of tries to start the addon.
# $3 delay in seconds between two consecutive tries
2015-06-25 04:55:40 +00:00
# $4 name of this object to use when logging about it.
# $5 namespace for this object
2016-10-11 23:22:02 +00:00
function create_resource_from_string( ) {
2015-03-13 22:34:00 +00:00
local -r config_string = $1 ;
2015-04-20 14:35:20 +00:00
local tries = $2 ;
2015-03-13 22:34:00 +00:00
local -r delay = $3 ;
2015-06-02 09:41:13 +00:00
local -r config_name = $4 ;
2015-06-25 04:55:40 +00:00
local -r namespace = $5 ;
2015-04-02 21:07:23 +00:00
while [ ${ tries } -gt 0 ] ; do
2016-08-11 01:08:01 +00:00
echo " ${ config_string } " | ${ KUBECTL } ${ KUBECTL_OPTS } --namespace= " ${ namespace } " apply -f - && \
2016-10-11 23:22:02 +00:00
log INFO " == Successfully started ${ config_name } in namespace ${ namespace } at $( date -Is) " && \
return 0;
2015-04-02 21:07:23 +00:00
let tries = tries-1;
2016-10-11 23:22:02 +00:00
log WRN " == Failed to start ${ config_name } in namespace ${ namespace } at $( date -Is) . ${ tries } tries remaining. == "
2015-04-02 21:07:23 +00:00
sleep ${ delay } ;
2015-03-11 20:42:41 +00:00
done
2015-04-02 21:07:23 +00:00
return 1;
2015-03-11 20:42:41 +00:00
}
2017-02-25 00:42:16 +00:00
function reconcile_addons( ) {
# TODO: Remove the first command in future release.
# Adding this for backward compatibility. Old addons have CLUSTER_SERVICE_LABEL=true and don't have
# ADDON_MANAGER_LABEL=EnsureExists will still be reconciled.
# Filter out `configured` message to not noisily log.
# `created`, `pruned` and errors will be logged.
log INFO "== Reconciling with deprecated label =="
${ KUBECTL } ${ KUBECTL_OPTS } apply --namespace= ${ SYSTEM_NAMESPACE } -f ${ ADDON_PATH } \
-l ${ CLUSTER_SERVICE_LABEL } = true,${ ADDON_MANAGER_LABEL } != EnsureExists \
2017-07-31 18:19:23 +00:00
--prune= true --recursive | grep -v configured
2017-02-25 00:42:16 +00:00
log INFO "== Reconciling with addon-manager label =="
${ KUBECTL } ${ KUBECTL_OPTS } apply --namespace= ${ SYSTEM_NAMESPACE } -f ${ ADDON_PATH } \
-l ${ CLUSTER_SERVICE_LABEL } != true,${ ADDON_MANAGER_LABEL } = Reconcile \
2017-07-31 18:19:23 +00:00
--prune= true --recursive | grep -v configured
2017-02-25 00:42:16 +00:00
log INFO " == Kubernetes addon reconcile completed at $( date -Is) == "
}
2016-10-11 23:22:02 +00:00
2017-02-25 00:42:16 +00:00
function ensure_addons( ) {
# Create objects already exist should fail.
# Filter out `AlreadyExists` message to not noisily log.
${ KUBECTL } ${ KUBECTL_OPTS } create --namespace= ${ SYSTEM_NAMESPACE } -f ${ ADDON_PATH } \
-l ${ ADDON_MANAGER_LABEL } = EnsureExists --recursive 2>& 1 | grep -v AlreadyExists
log INFO " == Kubernetes addon ensure completed at $( date -Is) == "
2016-10-11 23:22:02 +00:00
}
2017-11-10 08:10:53 +00:00
function is_leader( ) {
# In multi-master setup, only one addon manager should be running. We use
# existing leader election in kube-controller-manager instead of implementing
# a separate mechanism here.
if ! $ADDON_MANAGER_LEADER_ELECTION ; then
log INFO "Leader election disabled."
return 0;
fi
KUBE_CONTROLLER_MANAGER_LEADER = ` ${ KUBECTL } -n kube-system get ep kube-controller-manager \
-o go-template= $'{{index .metadata.annotations "control-plane.alpha.kubernetes.io/leader"}}' \
| sed 's/^.*"holderIdentity":"\([^"]*\)".*/\1/' `
# If there was any problem with getting the leader election results, var will
# be empty. Since it's better to have multiple addon managers than no addon
# managers at all, we're going to assume that we're the leader in such case.
log INFO " Leader is $KUBE_CONTROLLER_MANAGER_LEADER "
[ [ " $KUBE_CONTROLLER_MANAGER_LEADER " = = "" ||
" $HOSTNAME " = = " $KUBE_CONTROLLER_MANAGER_LEADER " ] ]
}
2015-04-02 21:07:23 +00:00
# The business logic for whether a given object should be created
# was already enforced by salt, and /etc/kubernetes/addons is the
# managed result is of that. Start everything below that directory.
2016-10-11 23:22:02 +00:00
log INFO " == Kubernetes addon manager started at $( date -Is) with ADDON_CHECK_INTERVAL_SEC= ${ ADDON_CHECK_INTERVAL_SEC } == "
2015-03-13 22:34:00 +00:00
2015-07-06 23:51:54 +00:00
# Create the namespace that will be used to host the cluster-level add-ons.
2016-05-05 17:51:32 +00:00
start_addon /opt/namespace.yaml 100 10 "" &
2015-07-06 23:51:54 +00:00
# Wait for the default service account to be created in the kube-system namespace.
2015-06-30 00:58:38 +00:00
token_found = ""
2015-06-30 13:51:10 +00:00
while [ -z " ${ token_found } " ] ; do
2015-06-30 00:58:38 +00:00
sleep .5
2016-10-31 04:08:11 +00:00
token_found = $( ${ KUBECTL } ${ KUBECTL_OPTS } get --namespace= " ${ SYSTEM_NAMESPACE } " serviceaccount default -o go-template= "{{with index .secrets 0}}{{.name}}{{end}}" )
if [ [ $? -ne 0 ] ] ; then
token_found = "" ;
log WRN "== Error getting default service account, retry in 0.5 second =="
fi
2015-06-30 00:58:38 +00:00
done
2016-10-11 23:22:02 +00:00
log INFO " == Default service account in the ${ SYSTEM_NAMESPACE } namespace has token ${ token_found } == "
2015-06-25 04:55:40 +00:00
2015-05-19 00:59:16 +00:00
# Create admission_control objects if defined before any other addon services. If the limits
# are defined in a namespace other than default, we should still create the limits for the
# default namespace.
for obj in $( find /etc/kubernetes/admission-controls \( -name \* .yaml -o -name \* .json \) ) ; do
2015-08-21 01:41:36 +00:00
start_addon " ${ obj } " 100 10 default &
2016-10-11 23:22:02 +00:00
log INFO " ++ obj ${ obj } is created ++ "
2015-05-19 00:59:16 +00:00
done
2016-10-11 23:22:02 +00:00
# Start the apply loop.
2015-06-02 09:41:13 +00:00
# Check if the configuration has changed recently - in case the user
# created/updated/deleted the files on the master.
2016-10-11 23:22:02 +00:00
log INFO " == Entering periodical apply loop at $( date -Is) == "
2015-06-02 09:41:13 +00:00
while true; do
2015-06-23 14:57:12 +00:00
start_sec = $( date +"%s" )
2017-11-10 08:10:53 +00:00
if is_leader; then
ensure_addons
reconcile_addons
else
log INFO "Not elected leader, going back to sleep."
fi
2015-06-23 14:57:12 +00:00
end_sec = $( date +"%s" )
len_sec = $(( ${ end_sec } - ${ start_sec } ))
# subtract the time passed from the sleep time
if [ [ ${ len_sec } -lt ${ ADDON_CHECK_INTERVAL_SEC } ] ] ; then
sleep_time = $(( ${ ADDON_CHECK_INTERVAL_SEC } - ${ len_sec } ))
sleep ${ sleep_time }
fi
2015-01-30 05:15:34 +00:00
done