2022-06-09 05:28:38 +00:00
|
|
|
#!/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:"
|
2022-09-02 00:30:59 +00:00
|
|
|
echo "1. Running the script with --type migrate to migrate the labels and annotations for Longhorn resources"
|
2022-06-09 05:28:38 +00:00
|
|
|
echo "2. Manually installing Longhorn chart in app&marketplace UI"
|
2022-09-02 00:30:59 +00:00
|
|
|
echo "3. Running script with --type cleanup to remove the old Longhorn chart from old catalog UI"
|
2022-06-09 05:28:38 +00:00
|
|
|
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
|
2022-09-02 00:30:59 +00:00
|
|
|
echo "Labels have not been migrated. Did you run the part 1 by specifying the flag --type migrate ?"
|
2022-06-09 05:28:38 +00:00
|
|
|
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"
|
2022-09-02 00:30:59 +00:00
|
|
|
echo " 6. Run this script again with the flag --type cleanup to remove the old chart from the legacy UI"
|