Skip to content

Commit 00705dc

Browse files
Merge pull request #1576 from percona/K8SPG-984-k8s-upgrade
K8SPG-984 add k8s-upgrade test for gke and doks
2 parents 6b3713c + 64cb7e3 commit 00705dc

25 files changed

Lines changed: 692 additions & 1 deletion

e2e-tests/functions

Lines changed: 234 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1744,4 +1744,237 @@ verify_hugepages_usage() {
17441744
echo "Hugepages available but NOT being used by PostgreSQL"
17451745
return 1
17461746
fi
1747-
}
1747+
}
1748+
1749+
get_available_k8s_versions() {
1750+
local offset="${1:-1}"
1751+
local platform="$2"
1752+
local region="$3"
1753+
local versions=""
1754+
1755+
case "$platform" in
1756+
digitalocean)
1757+
versions=$(doctl kubernetes options versions -o json \
1758+
| jq -r '.[].slug')
1759+
;;
1760+
1761+
gke)
1762+
versions=$(
1763+
gcloud container get-server-config \
1764+
--region "${region}" \
1765+
--format="value(validMasterVersions)" 2>/dev/null \
1766+
| tr ';' '\n' \
1767+
| awk -F'.' '!seen[$1"."$2]++'
1768+
)
1769+
;;
1770+
1771+
*)
1772+
echo "ERROR: unsupported platform '$platform'"
1773+
return 1
1774+
;;
1775+
esac
1776+
1777+
versions_sorted=$(echo "$versions" | sort -u -V)
1778+
echo "$versions_sorted" | tail -n "$offset" | head -n 1
1779+
}
1780+
1781+
create_k8s_cluster() {
1782+
local name="$1"
1783+
local version="$2"
1784+
local platform="$3"
1785+
local region="$4"
1786+
local ttl="${5:-"1"}"
1787+
1788+
case "$platform" in
1789+
1790+
digitalocean)
1791+
echo "Creating DOKS cluster: $name ($version)"
1792+
creation_time=$(date +%s)
1793+
doctl kubernetes cluster create "$name" \
1794+
--region "$region" \
1795+
--version "$version" \
1796+
--size "s-4vcpu-16gb-amd" \
1797+
--count "3" \
1798+
--tag "delete-cluster-after-hours:$ttl" \
1799+
--tag "creation-time:$creation_time" \
1800+
--tag "team:cloud" \
1801+
--tag "product:pg-operator" \
1802+
--wait
1803+
1804+
if [[ -n $DOKS_PROJECT ]]; then
1805+
project_id=$(doctl projects list --output json | jq -r --arg name "${DOKS_PROJECT}" '.[] | select(.name == $name) | .id')
1806+
cluster_id=$(doctl kubernetes cluster list --output json | jq -r --arg name "$name" '.[] | select(.name == $name) | .id')
1807+
urn=do:kubernetes:$cluster_id
1808+
doctl projects resources assign "$project_id" --resource "$urn"
1809+
fi
1810+
;;
1811+
1812+
gke)
1813+
echo "Creating GKE cluster: $name ($version)"
1814+
gcloud container clusters create "$name" \
1815+
--zone "$region" \
1816+
--cluster-ipv4-cidr=/21 \
1817+
--cluster-version "$version" \
1818+
--num-nodes "3" \
1819+
--machine-type "n1-standard-4" \
1820+
--labels="delete-cluster-after-hours=$ttl,team=cloud,product=pg-operator" \
1821+
--no-enable-autoupgrade \
1822+
--monitoring=NONE \
1823+
--logging=NONE \
1824+
--no-enable-managed-prometheus \
1825+
--quiet
1826+
1827+
kubectl create clusterrolebinding cluster-admin-binding1 \
1828+
--clusterrole=cluster-admin \
1829+
--user="$(gcloud config get-value core/account)"
1830+
;;
1831+
1832+
*)
1833+
echo "ERROR: unsupported platform '$platform'"
1834+
return 1
1835+
;;
1836+
esac
1837+
1838+
kubectl create namespace "${NAMESPACE}"
1839+
echo "Cluster $name created successfully"
1840+
}
1841+
1842+
upgrade_k8s_cluster() {
1843+
local name="$1"
1844+
local version="$2"
1845+
local platform="$(detect_k8s_platform)"
1846+
1847+
case "$platform" in
1848+
digitalocean)
1849+
echo "Upgrading DOKS cluster: $name to $version"
1850+
doctl kubernetes cluster upgrade "$name" \
1851+
--version "$version"
1852+
;;
1853+
gke)
1854+
echo "Upgrading GKE cluster: $name to $version"
1855+
location=$(gcloud container clusters list \
1856+
--filter="name=$name" \
1857+
--format="value(location)")
1858+
gcloud container clusters upgrade "$name" \
1859+
--master \
1860+
--cluster-version "$version" \
1861+
--zone "$location" \
1862+
--quiet
1863+
gcloud container clusters upgrade "$name" \
1864+
--node-pool default-pool \
1865+
--cluster-version "$version" \
1866+
--zone "$location" \
1867+
--quiet
1868+
;;
1869+
*)
1870+
echo "ERROR: unsupported platform '$platform'"
1871+
return 1
1872+
;;
1873+
esac
1874+
1875+
echo "Cluster $name upgraded to $version successfully"
1876+
}
1877+
1878+
delete_k8s_cluster() {
1879+
local name="$1"
1880+
local platform="$2"
1881+
local region="$3"
1882+
1883+
case "$platform" in
1884+
digitalocean)
1885+
echo "Deleting DOKS cluster: $name"
1886+
cluster_id=$(doctl kubernetes cluster list --output json | jq -r --arg name "$name" '.[] | select(.name == $name) | .id')
1887+
# Dangerous includes LoadBalancers, Volumes and all resources related to the cluster
1888+
doctl kubernetes cluster delete "$cluster_id" --force --dangerous
1889+
;;
1890+
gke)
1891+
echo "Deleting GKE cluster: $name"
1892+
gcloud container clusters delete "$name" \
1893+
--zone "$region" \
1894+
--quiet \
1895+
--async
1896+
;;
1897+
*)
1898+
echo "ERROR: unsupported platform '$platform'"
1899+
return 1
1900+
;;
1901+
esac
1902+
1903+
echo "Cluster $name deleted successfully"
1904+
}
1905+
1906+
get_k8s_cluster_name() {
1907+
local platform="${1:-$(detect_k8s_platform)}"
1908+
1909+
case "$platform" in
1910+
digitalocean)
1911+
local nodepool_id="$(kubectl get nodes -o jsonpath='{.items[0].metadata.labels.doks\.digitalocean\.com/node-pool-id}')"
1912+
doctl kubernetes cluster list -o json \
1913+
| jq -r --arg id "$nodepool_id" \
1914+
'.[] | select(.node_pools[]?.id == $id) | .name' 2>/dev/null
1915+
;;
1916+
gke)
1917+
kubectl get nodes -o jsonpath='{.items[0].spec.providerID}' \
1918+
| sed -E 's|.*gke-(.*)-default-pool.*|\1|'
1919+
;;
1920+
*)
1921+
echo "ERROR: unsupported platform '$platform'" >&2
1922+
return 1
1923+
;;
1924+
esac
1925+
}
1926+
1927+
get_k8s_cluster_version() {
1928+
local name="$1"
1929+
local platform="${2:-$(detect_k8s_platform)}"
1930+
1931+
case "$platform" in
1932+
digitalocean)
1933+
doctl kubernetes cluster get "$name" --output json \
1934+
| jq -r '.[0].version'
1935+
;;
1936+
gke)
1937+
location=$(gcloud container clusters list \
1938+
--filter="name=$name" \
1939+
--format="value(location)")
1940+
gcloud container clusters describe "$name" \
1941+
--zone "$location" \
1942+
--format="value(currentMasterVersion)"
1943+
;;
1944+
*)
1945+
echo "ERROR: unsupported platform '$platform'" >&2
1946+
return 1
1947+
;;
1948+
esac
1949+
}
1950+
1951+
get_k8s_nodes_version() {
1952+
kubectl get nodes -o json \
1953+
| jq -r '.items[].status.nodeInfo.kubeletVersion' \
1954+
| sort -u
1955+
}
1956+
1957+
verify_k8s_cluster_version() {
1958+
local cluster_name="$1"
1959+
local expected_version="$2"
1960+
local current_version="$(get_k8s_cluster_version "$cluster_name")"
1961+
1962+
if [[ $expected_version != "$current_version" ]]; then
1963+
echo "Error current cluster version $current_version is not the same as expected version $expected_version"
1964+
return 1
1965+
fi
1966+
}
1967+
1968+
verify_k8s_nodes_version() {
1969+
local expected_version="$1"
1970+
local nodes_version="$(get_k8s_nodes_version)"
1971+
local expected_clean="$(echo "$expected_version" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')" # Gets only Kubernetes version xx.xx.xx
1972+
1973+
for node_version in $nodes_version; do
1974+
node_clean=$(echo "$node_version" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')
1975+
if [[ $node_clean != "$expected_clean" ]]; then
1976+
echo "Error current node version $node_clean is not the same as expected version $expected_clean"
1977+
return 1
1978+
fi
1979+
done
1980+
}

e2e-tests/run-release.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ demand-backup-offline-snapshot
1010
dynamic-configuration
1111
finalizers
1212
init-deploy
13+
k8s-upgrade
1314
huge-pages
1415
major-upgrade-13-to-14
1516
major-upgrade-14-to-15
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
apiVersion: kuttl.dev/v1beta1
2+
kind: TestAssert
3+
timeout: 300
4+
commands:
5+
- script: |
6+
set -o errexit
7+
set -o xtrace
8+
9+
source ../../functions
10+
11+
expected_cluster_name=$(kubectl get configmap cluster-name -o jsonpath='{.data.name}' -n ${NAMESPACE})
12+
expected_version=$(kubectl get configmap initial-cluster-version -o jsonpath='{.data.version}' -n ${NAMESPACE})
13+
14+
until verify_k8s_cluster_version "$expected_cluster_name" "$expected_version"; do
15+
echo "Waiting for the cluster to state the version $expected_version..."
16+
sleep 10
17+
done
18+
19+
until verify_k8s_nodes_version "$expected_version"; do
20+
echo "Waiting for all nodes to state the version $expected_version..."
21+
kubectl get nodes
22+
sleep 10
23+
done
24+
25+
until [[ -z "$(kubectl get nodes --no-headers | awk '$2 != "Ready" {print}')" ]]; do
26+
echo "Waiting for all nodes to be Ready..."
27+
kubectl get nodes
28+
sleep 5
29+
done
30+
31+
cluster_name=$(get_k8s_cluster_name "${K8S_UPGRADE_PLATFORM}")
32+
if [[ "$expected_cluster_name" != "$cluster_name" ]]; then
33+
echo "Error current cluster $cluster_name is not the same as expected cluster name $expected_cluster_name"
34+
exit 1
35+
fi
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
apiVersion: kuttl.dev/v1beta1
2+
kind: TestStep
3+
commands:
4+
- timeout: 1000
5+
script: |-
6+
set -o errexit
7+
set -o xtrace
8+
9+
source ../../functions
10+
11+
name="k8s-upgrade-$RANDOM"
12+
13+
if [[ "${K8S_UPGRADE_PLATFORM}" != "gke" && "${K8S_UPGRADE_PLATFORM}" != "digitalocean" ]]; then
14+
echo "Unsupported platform: ${K8S_UPGRADE_PLATFORM}"
15+
exit 1
16+
fi
17+
18+
if [[ -n "${K8S_UPGRADE_INITIAL_VERSION}" && -z "${K8S_UPGRADE_FINAL_VERSION}" ]] ||
19+
[[ -z "${K8S_UPGRADE_INITIAL_VERSION}" && -n "${K8S_UPGRADE_FINAL_VERSION}" ]]; then
20+
echo "K8S_UPGRADE_INITIAL_VERSION and K8S_UPGRADE_FINAL_VERSION are both required when one is configured"
21+
exit 1
22+
fi
23+
24+
# By defautt, we will use the two most recent Kubernetes versions available for the specified platform and region
25+
initial_version="${K8S_UPGRADE_INITIAL_VERSION:-$(get_available_k8s_versions 2 "${K8S_UPGRADE_PLATFORM}" "${K8S_UPGRADE_REGION}")}"
26+
final_version="${K8S_UPGRADE_FINAL_VERSION:-$(get_available_k8s_versions 1 "${K8S_UPGRADE_PLATFORM}" "${K8S_UPGRADE_REGION}")}"
27+
28+
create_k8s_cluster "$name" "$initial_version" "${K8S_UPGRADE_PLATFORM}" "${K8S_UPGRADE_REGION}"
29+
30+
# Saving cluster information and available versions for the next test steps
31+
kubectl create configmap cluster-name \
32+
--from-literal=name="$name" \
33+
--namespace "${NAMESPACE}"
34+
35+
kubectl create configmap initial-cluster-version \
36+
--from-literal=version="$initial_version" \
37+
--namespace "${NAMESPACE}"
38+
39+
kubectl create configmap final-cluster-version \
40+
--from-literal=version="$final_version" \
41+
--namespace "${NAMESPACE}"
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
apiVersion: kuttl.dev/v1beta1
2+
kind: TestAssert
3+
metadata:
4+
name: check-operator-deploy-status
5+
timeout: 120
6+
commands:
7+
- script: |
8+
set -euo pipefail
9+
10+
kubectl assert exist-enhanced crd perconapgclusters.pgv2.percona.com
11+
kubectl assert exist-enhanced crd perconapgbackups.pgv2.percona.com
12+
kubectl assert exist-enhanced crd perconapgrestores.pgv2.percona.com
13+
kubectl assert exist-enhanced crd perconapgupgrades.pgv2.percona.com
14+
kubectl assert exist-enhanced deployment percona-postgresql-operator -n ${OPERATOR_NS:-$NAMESPACE} --field-selector status.readyReplicas=1
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
apiVersion: kuttl.dev/v1beta1
2+
kind: TestStep
3+
timeout: 10
4+
commands:
5+
- script: |-
6+
set -o errexit
7+
set -o xtrace
8+
9+
source ../../functions
10+
init_temp_dir # do this only in the first TestStep
11+
12+
deploy_operator
13+
deploy_client
14+
deploy_s3_secrets
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
apiVersion: kuttl.dev/v1beta1
2+
kind: TestAssert
3+
timeout: 600
4+
commands:
5+
- script: |
6+
verify_cluster() {
7+
kubectl assert exist-enhanced statefulset k8s-upgrade-repo-host -n ${NAMESPACE} \
8+
--field-selector status.readyReplicas=1 \
9+
--field-selector status.observedGeneration=1
10+
11+
for sts in $(kubectl get statefulset -n ${NAMESPACE} \
12+
-l postgres-operator.crunchydata.com/instance-set=instance1 \
13+
-o jsonpath='{.items[*].metadata.name}'); do
14+
kubectl assert exist-enhanced statefulset ${sts} -n ${NAMESPACE} \
15+
--field-selector status.readyReplicas=1 \
16+
--field-selector status.observedGeneration=1
17+
done
18+
19+
kubectl assert exist-enhanced deployment k8s-upgrade-pgbouncer -n ${NAMESPACE} \
20+
--field-selector status.readyReplicas=3
21+
22+
kubectl assert exist-enhanced postgrescluster k8s-upgrade -n ${NAMESPACE} \
23+
--field-selector status.proxy.pgBouncer.readyReplicas=3
24+
25+
kubectl assert exist-enhanced perconapgcluster k8s-upgrade -n ${NAMESPACE} \
26+
--field-selector status.state=ready \
27+
--field-selector metadata.generation=1
28+
}
29+
30+
until verify_cluster; do
31+
echo "Waiting for cluster to be ready..."
32+
sleep 10
33+
done

0 commit comments

Comments
 (0)