Skip to content
This repository has been archived by the owner on Nov 1, 2022. It is now read-only.

Commit

Permalink
e2e: test upgrade of chart with nested HelmRelease
Browse files Browse the repository at this point in the history
  • Loading branch information
hiddeco committed Feb 12, 2020
1 parent 9e6a19c commit 6b79a58
Show file tree
Hide file tree
Showing 9 changed files with 222 additions and 15 deletions.
56 changes: 46 additions & 10 deletions test/e2e/15_upgrade.bats
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ function setup() {
# Load libraries in setup() to access BATS_* variables
load lib/env
load lib/defer
load lib/helm
load lib/install
load lib/poll

Expand All @@ -22,12 +23,12 @@ function setup() {
kubectl create namespace "$DEMO_NAMESPACE"
}

@test "Git mutation causes upgrade" {
# Apply the HelmRelease fixtures
@test "When a mutation it Git is made, a release is upgraded" {
# Apply the HelmRelease fixture
kubectl apply -f "$FIXTURES_DIR/releases/git.yaml" >&3

# Wait for it to be deployed
poll_until_equals 'podinfo-git HelmRelease' 'deployed' "kubectl -n $DEMO_NAMESPACE get helmrelease/podinfo-git -o 'custom-columns=status:status.releaseStatus' --no-headers"
poll_until_equals 'release to be deployed' 'deployed' "kubectl -n $DEMO_NAMESPACE get helmrelease/podinfo-git -o 'custom-columns=status:status.releaseStatus' --no-headers"

# Clone the charts repository
local clone_dir
Expand All @@ -46,16 +47,16 @@ function setup() {
git push >&3

# Assert change is rolled out
poll_until_equals 'podinfo-git HelmRelease chart update' "successfully cloned chart revision: $head_hash" "kubectl -n $DEMO_NAMESPACE get helmrelease/podinfo-git -o jsonpath='{.status.conditions[?(@.type==\"ChartFetched\")].message}'"
poll_until_equals 'podinfo-git HelmRelease revision matches' "$head_hash" "kubectl -n $DEMO_NAMESPACE get helmrelease/podinfo-git -o jsonpath='{.status.revision}'"
poll_until_equals 'release chart update' "successfully cloned chart revision: $head_hash" "kubectl -n $DEMO_NAMESPACE get helmrelease/podinfo-git -o jsonpath='{.status.conditions[?(@.type==\"ChartFetched\")].message}'"
poll_until_equals 'revision match' "$head_hash" "kubectl -n $DEMO_NAMESPACE get helmrelease/podinfo-git -o jsonpath='{.status.revision}'"
}

@test "Git values.yaml change causes upgrade" {
# Apply the HelmRelease fixtures
@test "When a values.yaml change in Git is made, a release is upgraded" {
# Apply the HelmRelease fixture
kubectl apply -f "$FIXTURES_DIR/releases/git.yaml" >&3

# Wait for it to be deployed
poll_until_equals 'podinfo-git HelmRelease' 'deployed' "kubectl -n $DEMO_NAMESPACE get helmrelease/podinfo-git -o 'custom-columns=status:status.releaseStatus' --no-headers"
poll_until_equals 'release to be deployed' 'deployed' "kubectl -n $DEMO_NAMESPACE get helmrelease/podinfo-git -o 'custom-columns=status:status.releaseStatus' --no-headers"

# Clone the charts repository
local clone_dir
Expand All @@ -74,8 +75,43 @@ function setup() {
git push >&3

# Assert change is rolled out
poll_until_equals 'podinfo-git HelmRelease chart update' "successfully cloned chart revision: $head_hash" "kubectl -n $DEMO_NAMESPACE get helmrelease/podinfo-git -o jsonpath='{.status.conditions[?(@.type==\"ChartFetched\")].message}'"
poll_until_equals 'podinfo-git HelmRelease revision matches' "$head_hash" "kubectl -n $DEMO_NAMESPACE get helmrelease/podinfo-git -o jsonpath='{.status.revision}'"
poll_until_equals 'release chart update' "successfully cloned chart revision: $head_hash" "kubectl -n $DEMO_NAMESPACE get helmrelease/podinfo-git -o jsonpath='{.status.conditions[?(@.type==\"ChartFetched\")].message}'"
poll_until_equals 'revision match' "$head_hash" "kubectl -n $DEMO_NAMESPACE get helmrelease/podinfo-git -o jsonpath='{.status.revision}'"
}

@test "When a HelmRelease is nested in a chart, an upgrade does succeed" {
# Install chartmuseum
install_chartmuseum chartmuseum_result
# shellcheck disable=SC2154
local CHARTMUSEUM_URL="http://localhost:${chartmuseum_result[0]}"
# Teardown the created port-forward to chartmusem.
defer kill "${chartmuseum_result[1]}"

# Package and upload chart fixture
package_and_upload_chart "$FIXTURES_DIR/charts/nested-helmrelease" "$CHARTMUSEUM_URL"

# Apply the HelmRelease fixture
kubectl apply -f "$FIXTURES_DIR/releases/nested-helmrelease.yaml" >&3

# Wait for it and the child release to be deployed
poll_until_equals 'release to be deployed' 'deployed' "kubectl -n $DEMO_NAMESPACE get helmrelease/nested-helmrelease -o 'custom-columns=status:status.releaseStatus' --no-headers"
poll_until_equals 'child release to be deployed' 'deployed' "kubectl -n $DEMO_NAMESPACE get helmrelease/nested-helmrelease-child -o 'custom-columns=status:status.releaseStatus' --no-headers"

releaseGen=$(kubectl -n "$DEMO_NAMESPACE" get helmrelease/nested-helmrelease -o 'custom-columns=status:status.observedGeneration' --no-headers)
childReleaseGen=$(kubectl -n "$DEMO_NAMESPACE" get helmrelease/nested-helmrelease -o 'custom-columns=status:status.observedGeneration' --no-headers)

# Patch release
kubectl patch -f "$FIXTURES_DIR/releases/nested-helmrelease.yaml" --type='json' -p='[{"op": "replace", "path": "/spec/values/nested/deeper/deepest/image/tag", "value": "1.1.0"}]' >&3

# Wait for patch to be processed
poll_until_equals 'patch to be processed for release' "$((releaseGen+1))" "kubectl -n $DEMO_NAMESPACE get helmrelease/nested-helmrelease -o 'custom-columns=status:status.observedGeneration' --no-headers"
poll_until_equals 'patch to be processed for child release' "$((childReleaseGen+1))" "kubectl -n $DEMO_NAMESPACE get helmrelease/nested-helmrelease -o 'custom-columns=status:status.observedGeneration' --no-headers"

# Assert successful release
releaseStatus=$(kubectl -n "$DEMO_NAMESPACE" get helmrelease/nested-helmrelease -o jsonpath='{.status.conditions[?(@.type==\"Released\")].reason}')
[ "$releaseStatus" = "HelmSuccess" ]
childReleaseStatus=$(kubectl -n "$DEMO_NAMESPACE" get helmrelease/nested-helmrelease-child -o jsonpath='{.status.conditions[?(@.type==\"Released\")].reason}')
[ "$childReleaseStatus" = "HelmSuccess" ]
}

function teardown() {
Expand Down
4 changes: 4 additions & 0 deletions test/e2e/fixtures/charts/nested-helmrelease/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
apiVersion: v1
description: Nested HelmRelease chart
name: nested-helmrelease
version: 0.1.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
apiVersion: helm.fluxcd.io/v1
kind: HelmRelease
metadata:
name: {{ .Release.Name }}-child
namespace: {{ .Release.Namespace }}
spec:
releaseName: {{ .Release.Name }}-child
chart:
repository: https://stefanprodan.github.io/podinfo
version: 3.2.0
name: podinfo
values:
{{- toYaml .Values.nested.deeper.deepest | nindent 4 }}
6 changes: 6 additions & 0 deletions test/e2e/fixtures/charts/nested-helmrelease/values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
nested:
deeper:
deepest:
image:
name: some-other-image
tag: 1.0.1
75 changes: 75 additions & 0 deletions test/e2e/fixtures/kustom/base/chartmuseum/chartmuseum.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
name: chartmuseum
name: chartmuseum
spec:
replicas: 1
selector:
matchLabels:
name: chartmuseum
template:
metadata:
labels:
name: chartmuseum
spec:
containers:
- name: chartmuseum
image: chartmuseum/chartmuseum:v0.11.0
imagePullPolicy: IfNotPresent
env:
- name: "LOG_JSON"
value: "true"
- name: "STORAGE"
value: "local"
args:
- --port=8080
- --storage-local-rootdir=/storage
livenessProbe:
httpGet:
path: /health
port: http
failureThreshold: 3
initialDelaySeconds: 5
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
readinessProbe:
httpGet:
path: /health
port: http
failureThreshold: 3
initialDelaySeconds: 5
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
ports:
- containerPort: 8080
name: http
protocol: TCP
volumeMounts:
- mountPath: /storage
name: storage-volume
securityContext:
fsGroup: 1000
volumes:
- name: storage-volume
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
labels:
name: chartmuseum
name: chartmuseum
spec:
ports:
- name: http
port: 8080
protocol: TCP
targetPort: http
selector:
name: chartmuseum
type: ClusterIP
2 changes: 2 additions & 0 deletions test/e2e/fixtures/kustom/base/chartmuseum/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
resources:
- chartmuseum.yaml
19 changes: 19 additions & 0 deletions test/e2e/fixtures/releases/nested-helmrelease.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
apiVersion: helm.fluxcd.io/v1
kind: HelmRelease
metadata:
name: nested-helmrelease
namespace: demo
spec:
releaseName: nested-helmrelease
chart:
repository: http://chartmuseum:8080
name: nested-helmrelease
version: 0.1.0
values:
nested:
deeper:
deepest:
image:
name: some-other-image
tag: 1.0.1
23 changes: 23 additions & 0 deletions test/e2e/lib/helm.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/env bash

# shellcheck disable=SC1090
source "${E2E_DIR}/lib/defer.bash"

function package_and_upload_chart() {
local chart=${1}
local chart_repository=${2}

gen_dir=$(mktemp -d)
defer rm -rf "'$gen_dir'"

# Package
if [ "$HELM_VERSION" == "v3" ]; then
helm3 package --destination "$gen_dir" "$chart"
else
helm2 package --destination "$gen_dir" "$chart"
fi

# Upload
chart_tarbal=$(find "$gen_dir" -type f -name "*.tgz" | head -n1)
curl --data-binary "@$chart_tarbal" "$chart_repository/api/charts"
}
38 changes: 33 additions & 5 deletions test/e2e/lib/install.bash
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,8 @@ function install_git_srv() {
local kustomization_dir=${2:-base/gitsrv}
local gen_dir
gen_dir=$(mktemp -d)

ssh-keygen -t rsa -N "" -f "$gen_dir/id_rsa"
defer rm -rf "'$gen_dir'"
ssh-keygen -t rsa -N "" -f "$gen_dir/id_rsa"
kubectl create secret generic flux-git-deploy \
--namespace="${E2E_NAMESPACE}" \
--from-file="${FIXTURES_DIR}/known_hosts" \
Expand Down Expand Up @@ -87,8 +86,37 @@ function install_git_srv() {
}

function uninstall_git_srv() {
local secret_name=${1:-flux-git-deploy}
local kustomization_dir=${1:-base/gitsrv}

# Silence secret deletion errors since the secret can be missing (deleted by uninstalling Flux)
kubectl delete -n "${E2E_NAMESPACE}" secret "$secret_name" &> /dev/null
kubectl delete -n "${E2E_NAMESPACE}" -f "${FIXTURES_DIR}/gitsrv.yaml"
kubectl delete -n "${E2E_NAMESPACE}" secret flux-git-deploy &> /dev/null
kubectl delete -n "${E2E_NAMESPACE}" -k "${FIXTURES_DIR}/kustom/${kustomization_dir}" >&3
}

function install_chartmuseum() {
local external_access_result_var=${1}
local kustomization_dir=${2:-base/chartmuseum}

kubectl apply -n "${E2E_NAMESPACE}" -k "${FIXTURES_DIR}/kustom/${kustomization_dir}" >&3

# Wait for the chartmuseum to become ready
kubectl -n "${E2E_NAMESPACE}" rollout status deployment/chartmuseum

if [ -n "$external_access_result_var" ]; then
local chartmuseum_podname
chartmuseum_podname=$(kubectl get pod -n "${E2E_NAMESPACE}" -l name=chartmuseum -o jsonpath="{['items'][0].metadata.name}")
coproc kubectl port-forward -n "${E2E_NAMESPACE}" "$chartmuseum_podname" :8080
local local_port
read -r local_port <&"${COPROC[0]}"-
# shellcheck disable=SC2001
local_port=$(echo "$local_port" | sed 's%.*:\([0-9]*\).*%\1%')
# return the ssh command needed for git, and the PID of the port-forwarding PID into a variable of choice
eval "${external_access_result_var}=('$local_port' '$COPROC_PID')"
fi
}

function uninstall_chartmuseum() {
local kustomization_dir=${1:-base/chartmuseum}

kubectl delete -n "${E2E_NAMESPACE}" -k "${FIXTURES_DIR}/kustom/${kustomization_dir}" >&3
}

0 comments on commit 6b79a58

Please sign in to comment.