#!/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 setglobal KUBE_ROOT = "$[dirname $(BASH_SOURCE)]/.." source "$(KUBE_ROOT)/hack/lib/init.sh" setglobal 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" ) # Find all the namespaces. setglobal namespaces = ''( $("${KUBECTL}" get namespaces -o go-template="{{range.items}}{{.metadata.name}} {{end}}")) if test -z $(namespaces:-) { echo "Unexpected: No namespace found. Nothing to do." exit 1 } setglobal all_failed = '1' for resource in [$(resources[@])] { for namespace in [$(namespaces[@])] { # 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 setglobal instances = ''( $("${KUBECTL}" get "${resource}" --namespace="${namespace}" -o go-template="{{range.items}}{{.metadata.name}} {{end}}")) setglobal result = $Status set -e if [[ "${all_failed}" -eq 1 && "${result}" -eq 0 ]] { setglobal all_failed = '0' } # Nothing to do if there is no instance of that resource. if [[ -z "${instances:-}" ]] { continue } for instance in [$(instances[@])] { # 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. setglobal 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 ]] { echo "Error: failed to update $(resource)/$(instance) in $(namespace) namespace after 5 tries" exit 1 } } if [[ "${resource}" == "namespaces" ]] || [[ "${resource}" == "nodes" ]] { # These resources are namespace agnostic. No need to update them for every # namespace. break } } } if [[ "${all_failed}" -eq 1 ]] { echo "kubectl get failed for all resources" exit 1 } echo "All objects updated successfully!!" exit 0