#!/bin/bash # Copyright 2015 The Kubernetes Authors. # # 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. # Script to update etcd objects as per the latest API Version. # This just reads all objects and then writes them back as is to ensure that # they are written using the latest API version. # # Steps to use this script to upgrade the cluster to a new version: # https://kubernetes.io/docs/tasks/administer-cluster/cluster-management/#upgrading-to-a-different-api-version set -o errexit set -o nounset set -o pipefail KUBE_ROOT=$(dirname "${BASH_SOURCE}")/.. source "${KUBE_ROOT}/hack/lib/init.sh" KUBECTL="${KUBE_OUTPUT_HOSTBIN}/kubectl" # List of resources to be updated. # TODO: Get this list of resources from server once # http://issue.k8s.io/2057 is fixed. declare -a resources=( "endpoints" "events" "limitranges" "namespaces" "nodes" "pods" "persistentvolumes" "persistentvolumeclaims" "replicationcontrollers" "resourcequotas" "secrets" "services" "jobs" "horizontalpodautoscalers" "storageclasses" "roles.rbac.authorization.k8s.io" "rolebindings.rbac.authorization.k8s.io" "clusterroles.rbac.authorization.k8s.io" "clusterrolebindings.rbac.authorization.k8s.io" "networkpolicies.networking.k8s.io" ) # Find all the namespaces. namespaces=( $("${KUBECTL}" get namespaces -o go-template="{{range.items}}{{.metadata.name}} {{end}}")) if [ -z "${namespaces:-}" ] then echo "Unexpected: No namespace found. Nothing to do." exit 1 fi all_failed=1 for resource in "${resources[@]}" do for namespace in "${namespaces[@]}" do # If get fails, assume it's because the resource hasn't been installed in the apiserver. # TODO hopefully we can remove this once we use dynamic discovery of gettable/updateable # resources. set +e instances=( $("${KUBECTL}" get "${resource}" --namespace="${namespace}" -o go-template="{{range.items}}{{.metadata.name}} {{end}}")) result=$? set -e if [[ "${all_failed}" -eq 1 && "${result}" -eq 0 ]]; then all_failed=0 fi # Nothing to do if there is no instance of that resource. if [[ -z "${instances:-}" ]] then continue fi for instance in "${instances[@]}" do # Read and then write it back as is. # Update can fail if the object was updated after we fetched the # object, but before we could update it. We, hence, try the update # operation multiple times. But 5 continuous failures indicate some other # problem. success=0 for (( tries=0; tries<5; ++tries )) do filename="/tmp/k8s-${namespace}-${resource}-${instance}.json" ( "${KUBECTL}" get "${resource}" "${instance}" --namespace="${namespace}" -o json > "${filename}" ) || true if [[ ! -s "${filename}" ]] then # This happens when the instance has been deleted. We can hence ignore # this instance. echo "Looks like ${instance} got deleted. Ignoring it" continue fi output=$("${KUBECTL}" replace -f "${filename}" --namespace="${namespace}") || true rm "${filename}" if [ -n "${output:-}" ] then success=1 break fi done if [[ "${success}" -eq 0 ]] then echo "Error: failed to update ${resource}/${instance} in ${namespace} namespace after 5 tries" exit 1 fi done if [[ "${resource}" == "namespaces" ]] || [[ "${resource}" == "nodes" ]] then # These resources are namespace agnostic. No need to update them for every # namespace. break fi done done if [[ "${all_failed}" -eq 1 ]]; then echo "kubectl get failed for all resources" exit 1 fi echo "All objects updated successfully!!" exit 0