longhorn/scripts/longhorn_rancher_chart_migration.sh

202 lines
7.8 KiB
Bash
Raw Permalink Normal View History

#!/bin/bash
#set -x
kubectl get-all version &> /dev/null
if [ $? -ne 0 ]; then
echo "ERROR: command (kubectl get-all) is not found. Please install it here: https://github.com/corneliusweig/ketall#installation"
exit 1
fi
set -e
usage() {
echo ""
echo "The migration includes:"
echo "1. Running the script with --type migrate to migrate the labels and annotations for Longhorn resources"
echo "2. Manually installing Longhorn chart in app&marketplace UI"
echo "3. Running script with --type cleanup to remove the old Longhorn chart from old catalog UI"
echo ""
echo "usage:"
echo "$0 [options]"
echo " -u | --upstream-kubeconfig: upstream rancher cluster kubeconfig path"
echo " -d | --downstream-kubeconfig: downstream cluster kubeconfig path"
echo " -t | --type: specify the type you want to run (migrate or cleanup)"
echo " --dry-run: do not run migriation"
echo ""
echo "example:"
echo " $0 -u /path/to/upstream/rancher/cluster/kubeconfig -d /path/to/downstream/cluster/kubeconfig"
}
SCRIPT_DIR="$(dirname "$0")"
UPSTREAM_KUBECONFIG=""
DOWNSTREAM_KUBECONFIG=""
KUBECTL_DRY_RUN=""
while [ "$1" != "" ]; do
case $1 in
-u | --upstream-kubeconfig)
shift
UPSTREAM_KUBECONFIG="$1"
;;
-d | --downstream-kubeconfig)
shift
DOWNSTREAM_KUBECONFIG="$1"
;;
-t | --type)
shift
TYPE="$1"
;;
--dry-run)
KUBECTL_DRY_RUN="--dry-run=client"
;;
*)
usage
exit 1
;;
esac
shift
done
if [ -z "$UPSTREAM_KUBECONFIG" ]; then
echo "--upstream-kubeconfig is mandatory"
usage
exit 1
fi
if [ -z "$DOWNSTREAM_KUBECONFIG" ]; then
echo "--downstream-kubeconfig is mandatory"
usage
exit 1
fi
if [ "$TYPE" != "migrate" ] && [ "$TYPE" != "cleanup" ] ; then
echo "--type must be set to migrate or cleanup"
usage
exit 1
fi
# Longhorn Namespace
RELEASE_NAMESPACE=longhorn-system
# Longhorn Release Name
RELEASE_NAME=longhorn-system
echo "Looking up Rancher Project App '${RELEASE_NAME}' ..."
DOWNSTREAMCLUSTERID=$(cat ${DOWNSTREAM_KUBECONFIG} | grep "server:.*https://.*/k8s/clusters/.*" | awk -F'/' '{print $(NF)}' | awk -F'"' '{print $1}')
RANCHERAPP=$(kubectl --kubeconfig ${UPSTREAM_KUBECONFIG} get --all-namespaces apps.project.cattle.io -o jsonpath='{range.items[*]}{.metadata.namespace} {.metadata.name} {.spec.targetNamespace} {.spec.projectName} {.spec.externalId}{"\n"}{end}' | grep -s "${RELEASE_NAME} ${RELEASE_NAMESPACE} ${DOWNSTREAMCLUSTERID}")
RANCHERAPPNS=$(echo "${RANCHERAPP}" | awk '{print $1}')
RANCHERAPPEXTERNALID=$(echo "${RANCHERAPP}" | awk '{print $5}')
RANCHERAPPCATALOG=$(echo "${RANCHERAPPEXTERNALID}" | sed -n 's/.*catalog=\(.*\)/\1/p' | awk -F '&' '{print $1}' | sed 's/migrated-//')
RANCHERAPPTEMPLATE=$(echo "${RANCHERAPPEXTERNALID}" | sed -n 's/.*template=\(.*\)/\1/p' | awk -F '&' '{print $1}')
RANCHERAPPTEMPLATEVERSION=$(echo "${RANCHERAPPEXTERNALID}" | sed -n 's/.*version=\(.*\)/\1/p' | awk -F '&' '{print $1}')
RANCHERAPPVALUES=""
RANCHERAPPANSWERS=""
if [ -z "$DOWNSTREAMCLUSTERID" ] || [ -z "$RANCHERAPP" ] || [ -z "$RANCHERAPPNS" ] || [ -z "$RANCHERAPPCATALOG" ] || [ -z "$RANCHERAPPTEMPLATE" ] || [ -z "$RANCHERAPPTEMPLATEVERSION" ]; then
echo "Rancher Project App '${RELEASE_NAME}' not found!"
exit 1
fi
RANCHERAPPVALUES=$(kubectl --kubeconfig ${UPSTREAM_KUBECONFIG} -n ${RANCHERAPPNS} get apps.project.cattle.io ${RELEASE_NAME} -o go-template='{{if .spec.valuesYaml}}{{.spec.valuesYaml}}{{end}}')
if [ -z "${RANCHERAPPVALUES}" ]; then
RANCHERAPPANSWERS=$(kubectl --kubeconfig ${UPSTREAM_KUBECONFIG} -n ${RANCHERAPPNS} get apps.project.cattle.io ${RELEASE_NAME} -o go-template='{{if .spec.answers}}{{range $key,$value := .spec.answers}}{{$key}}: {{$value}}{{"\n"}}{{end}}{{end}}' | sed 's/: /=/' | sed 's/$/,/' | sed '$ s/.$//' | tr -d '\n')
fi
if [ -z "${RANCHERAPPVALUES:-$RANCHERAPPANSWERS}" ]; then
echo "No valid answers found!"
exit 1
fi
echo ""
echo "Rancher Project App '${RELEASE_NAME}' found:"
echo " Project-Namespace: ${RANCHERAPPNS}"
echo " Downstream-Cluster: ${DOWNSTREAMCLUSTERID}"
echo " Catalog: ${RANCHERAPPCATALOG}"
echo " Template: ${RANCHERAPPTEMPLATE} (${RANCHERAPPTEMPLATEVERSION})"
echo " Answers:"
printf '%s\n' "${RANCHERAPPVALUES:-$RANCHERAPPANSWERS}"
echo ""
if [ "$TYPE" == "cleanup" ] ; then
MANAGER=$(kubectl --kubeconfig ${DOWNSTREAM_KUBECONFIG} -n ${RELEASE_NAMESPACE} get ds longhorn-manager -ojsonpath="{.metadata.labels['app\.kubernetes\.io/managed-by']}")
if [ $MANAGER != "Helm" ] ; then
echo "Labels have not been migrated. Did you run the part 1 by specifying the flag --type migrate ?"
exit 1
fi
echo ""
echo "Patching Project App Catalog ..."
kubectl --kubeconfig ${UPSTREAM_KUBECONFIG} -n ${RANCHERAPPNS} ${KUBECTL_DRY_RUN} patch apps.project.cattle.io ${RELEASE_NAME} --type=merge --patch-file=/dev/stdin <<-EOF
{
"metadata": {
"annotations": {
"cattle.io/skipUninstall": "true",
"catalog.cattle.io/ui-source-repo": "helm3-library",
"catalog.cattle.io/ui-source-repo-type": "cluster",
"apps.cattle.io/migrated": "true"
}
}
}
EOF
if [ $? -ne 0 ]; then
echo "Failed Patching Project App Catalog"
exit 1
fi
echo ""
echo "Deleting Project App Catalog ..."
kubectl --kubeconfig ${UPSTREAM_KUBECONFIG} -n ${RANCHERAPPNS} ${KUBECTL_DRY_RUN} delete apps.project.cattle.io ${RELEASE_NAME}
exit 0
fi
echo ""
echo ""
echo "Checking concurrent-automatic-engine-upgrade-per-node-limit setting ..."
SETTING=$(kubectl --kubeconfig ${DOWNSTREAM_KUBECONFIG} -n ${RELEASE_NAMESPACE} get settings.longhorn.io concurrent-automatic-engine-upgrade-per-node-limit -ojsonpath="{.value}")
if [ "$SETTING" != "0" ]; then
echo "concurrent-automatic-engine-upgrade-per-node-limit must be set to 0 before the migration"
exit 1
fi
echo ""
echo ""
echo "Looking up existing Resources ..."
RESOURCES=$(kubectl get-all --kubeconfig ${DOWNSTREAM_KUBECONFIG} --exclude AppRevision -o name -l io.cattle.field/appId=${RELEASE_NAME} 2>/dev/null | sort)
if [[ "$RESOURCES" == "No resources"* ]]; then
RESOURCES=""
fi
echo ""
echo "Patching CRD Resources ..."
for resource in $RESOURCES; do
if [[ $resource == "customresourcedefinition.apiextensions.k8s.io/"* ]]; then
kubectl --kubeconfig ${DOWNSTREAM_KUBECONFIG} -n ${RELEASE_NAMESPACE} ${KUBECTL_DRY_RUN} annotate --overwrite ${resource} "meta.helm.sh/release-name"="longhorn-crd" "meta.helm.sh/release-namespace"="${RELEASE_NAMESPACE}" "helm.sh/resource-policy"="keep"
kubectl --kubeconfig ${DOWNSTREAM_KUBECONFIG} -n ${RELEASE_NAMESPACE} ${KUBECTL_DRY_RUN} label --overwrite ${resource} "app.kubernetes.io/managed-by"="Helm"
fi
done
echo ""
echo "Patching Other Resources ..."
for resource in $RESOURCES; do
if [[ $resource == "customresourcedefinition.apiextensions.k8s.io/"* ]]; then
continue
fi
kubectl --kubeconfig ${DOWNSTREAM_KUBECONFIG} -n ${RELEASE_NAMESPACE} ${KUBECTL_DRY_RUN} annotate --overwrite ${resource} "meta.helm.sh/release-name"="longhorn" "meta.helm.sh/release-namespace"="${RELEASE_NAMESPACE}"
kubectl --kubeconfig ${DOWNSTREAM_KUBECONFIG} -n ${RELEASE_NAMESPACE} ${KUBECTL_DRY_RUN} label --overwrite ${resource} "app.kubernetes.io/managed-by"="Helm"
done
echo ""
echo "-----------------------------"
echo "Successfully updated the annotations and labels for the resources!"
echo "Next step:"
echo " 1. Go to Rancher UI -> Go to the downstream cluster -> App&Marketplace -> Charts"
echo " 2. Find and select the Longhorn chart"
echo " 3. Select the chart version corresponding the Longhorn version ${RANCHERAPPTEMPLATEVERSION}"
echo " 4. Install the chart with the correct helm values. Here are the helm values of your old charts: "
printf '%s\n' "${RANCHERAPPVALUES:-$RANCHERAPPANSWERS}"
echo " 5. Verify that the migrated charts are working ok"
echo " 6. Run this script again with the flag --type cleanup to remove the old chart from the legacy UI"