Skip to content

Commit 43f7611

Browse files
committed
feat: create a multi-path hyperconverged lab deployment
This change implements a code path for both Kubespray and Talos as a deployment target, building upon the test framework that we're creating. Signed-off-by: Kevin Carter <[email protected]>
1 parent 87aff28 commit 43f7611

15 files changed

+3456
-1430
lines changed
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
---
2+
name: Running hyperconverged smoke tests
3+
4+
"on":
5+
workflow_dispatch:
6+
inputs:
7+
acmeEmail:
8+
description: Set email for ACME
9+
required: true
10+
default: "[email protected]"
11+
type: string
12+
gatewayDomain:
13+
description: Set domain for the gateway
14+
required: true
15+
default: cloud.local
16+
type: string
17+
sshUsername:
18+
description: Set SSH username
19+
required: true
20+
default: "ubuntu"
21+
type: choice
22+
options:
23+
- "ubuntu"
24+
- "debian"
25+
mode:
26+
description: Set mode
27+
required: true
28+
default: "test"
29+
type: choice
30+
options:
31+
- "test"
32+
- "deploy"
33+
- "cleanup"
34+
run_tests:
35+
description: Run post-deployment tests
36+
required: false
37+
default: true
38+
type: boolean
39+
test_level:
40+
description: Test level to run
41+
required: false
42+
default: "quick"
43+
type: choice
44+
options:
45+
- "quick"
46+
- "standard"
47+
- "full"
48+
pull_request:
49+
paths:
50+
- ansible/**
51+
- base-kustomize/**
52+
- base-helm-configs/**
53+
- bin/**
54+
- scripts/**
55+
- ".github/workflows/smoke-deploy-lab.yaml"
56+
57+
env:
58+
HYPERCONVERGED_DEV: "true"
59+
GATEWAY_DOMAIN: cloud.local
60+
OS_FLAVOR: gp.5.8.16
61+
JUMP_HOST_FLAVOR: gp.5.2.2
62+
ACME_EMAIL: [email protected]
63+
SSH_USERNAME: "ubuntu"
64+
TEST_LEVEL: "quick"
65+
66+
jobs:
67+
smoke-deploy:
68+
runs-on: self-hosted
69+
container:
70+
image: localhost:5000/genestack-ci:latest
71+
steps:
72+
- name: Checkout repository
73+
uses: actions/checkout@v4
74+
75+
- name: Dynamically set MY_DATE environment variable
76+
if: ${{ github.event_name == 'pull_request' }}
77+
run: echo "LAB_NAME_PREFIX=smoke-$(date +%s)" >> $GITHUB_ENV
78+
79+
- name: Statically set environment variable
80+
if: ${{ github.event_name == 'workflow_dispatch' }}
81+
run: |
82+
echo "LAB_NAME_PREFIX=$(echo '${{ github.event.inputs.gatewayDomain }}' | tr '.' '-')" >> $GITHUB_ENV
83+
echo "GATEWAY_DOMAIN=${{ github.event.inputs.gatewayDomain }}" >> $GITHUB_ENV
84+
echo "ACME_EMAIL=${{ github.event.inputs.acmeEmail }}" >> $GITHUB_ENV
85+
echo "SSH_USERNAME=${{ github.event.inputs.sshUsername }}" >> $GITHUB_ENV
86+
87+
- name: Run deployment script
88+
if: ${{ github.event_name == 'pull_request' || contains(fromJSON('["deploy", "test"]'), github.event.inputs.mode) }}
89+
run: |
90+
eval "$(ssh-agent -s)"
91+
export TEST_LEVEL="${{ github.event.inputs.test_level }}"
92+
scripts/hyperconverged-lab.sh talos
93+
94+
- name: Retrieve Keys
95+
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'deploy' }}
96+
uses: actions/upload-artifact@v4
97+
with:
98+
name: ssh-keys
99+
if-no-files-found: warn # 'warn' or 'ignore' are also available, defaults to `warn`
100+
path: "/github/home/.ssh/${{ env.LAB_NAME_PREFIX }}-key.pem"
101+
102+
- name: Create output file in markdown format
103+
run: |
104+
if [ -s /tmp/output.txt ]; then
105+
echo "### Cloud Access" > access-output.txt
106+
cat /tmp/output.txt >> access-output.txt
107+
fi
108+
109+
- name: Publish Output to Summary
110+
run: |
111+
if [ -s access-output.txt ]; then
112+
{
113+
cat access-output.txt
114+
} >> $GITHUB_STEP_SUMMARY
115+
fi
116+
117+
- name: Upload Test Results
118+
if: ${{ always() && (github.event_name == 'pull_request' || (github.event.inputs.run_tests == 'true' && contains(fromJSON('["deploy", "test"]'), github.event.inputs.mode))) }}
119+
uses: actions/upload-artifact@v4
120+
with:
121+
name: test-results-${{ github.run_number }}
122+
path: test-results/
123+
if-no-files-found: ignore
124+
retention-days: 30
125+
126+
- name: Publish Test Summary
127+
if: ${{ always() && (github.event_name == 'pull_request' || (github.event.inputs.run_tests == 'true' && contains(fromJSON('["deploy", "test"]'), github.event.inputs.mode))) }}
128+
run: |
129+
echo "## Test Results" >> $GITHUB_STEP_SUMMARY
130+
echo "" >> $GITHUB_STEP_SUMMARY
131+
132+
if [ -f test-results/aggregate-results.txt ]; then
133+
echo "### Test Suite Summary" >> $GITHUB_STEP_SUMMARY
134+
echo "" >> $GITHUB_STEP_SUMMARY
135+
echo "| Test Suite | Status |" >> $GITHUB_STEP_SUMMARY
136+
echo "|------------|--------|" >> $GITHUB_STEP_SUMMARY
137+
138+
while IFS=: read -r suite status; do
139+
status=$(echo "$status" | xargs)
140+
if [ "$status" = "PASSED" ]; then
141+
echo "| $suite | :white_check_mark: PASSED |" >> $GITHUB_STEP_SUMMARY
142+
else
143+
echo "| $suite | :x: FAILED |" >> $GITHUB_STEP_SUMMARY
144+
fi
145+
done < test-results/aggregate-results.txt
146+
147+
echo "" >> $GITHUB_STEP_SUMMARY
148+
fi
149+
150+
# Parse XML results if available
151+
if ls test-results/*.xml >/dev/null 2>&1; then
152+
echo "### Detailed Test Results" >> $GITHUB_STEP_SUMMARY
153+
echo "" >> $GITHUB_STEP_SUMMARY
154+
155+
for xml_file in test-results/*.xml; do
156+
if [ -f "$xml_file" ]; then
157+
suite_name=$(grep -o 'name="[^"]*"' "$xml_file" | head -1 | sed 's/name="//;s/"//')
158+
echo "#### $suite_name" >> $GITHUB_STEP_SUMMARY
159+
echo "" >> $GITHUB_STEP_SUMMARY
160+
echo "| Test | Status |" >> $GITHUB_STEP_SUMMARY
161+
echo "|------|--------|" >> $GITHUB_STEP_SUMMARY
162+
163+
grep -o '<testcase name="[^"]*"' "$xml_file" | sed 's/<testcase name="//;s/"$//' | while read test; do
164+
if grep -q "name=\"${test}\".*<failure" "$xml_file"; then
165+
echo "| $test | :x: Failed |" >> $GITHUB_STEP_SUMMARY
166+
elif grep -q "name=\"${test}\".*<skipped" "$xml_file"; then
167+
echo "| $test | :warning: Skipped |" >> $GITHUB_STEP_SUMMARY
168+
else
169+
echo "| $test | :white_check_mark: Passed |" >> $GITHUB_STEP_SUMMARY
170+
fi
171+
done
172+
173+
echo "" >> $GITHUB_STEP_SUMMARY
174+
fi
175+
done
176+
fi
177+
178+
if [ ! -f test-results/aggregate-results.txt ] && ! ls test-results/*.xml >/dev/null 2>&1; then
179+
echo "_No test results available_" >> $GITHUB_STEP_SUMMARY
180+
fi
181+
182+
- name: Cleanup the lab
183+
if: ${{ always() && (github.event_name == 'pull_request' || contains(fromJSON('["cleanup", "test"]'), github.event.inputs.mode)) }}
184+
run: scripts/hyperconverged-lab-uninstall.sh talos

.github/workflows/smoke-deploy-lab.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ env:
6868
GATEWAY_DOMAIN: cloud.local
6969
ACME_EMAIL: [email protected]
7070
OS_IMAGE: "Ubuntu 24.04"
71+
OS_FLAVOR: gp.5.8.16
7172
SSH_USERNAME: "ubuntu"
7273
TEST_LEVEL: "quick"
7374

@@ -98,7 +99,7 @@ jobs:
9899
run: |
99100
eval "$(ssh-agent -s)"
100101
export TEST_LEVEL="${{ github.event.inputs.test_level }}"
101-
scripts/hyperconverged-lab.sh
102+
scripts/hyperconverged-lab.sh kubespray
102103
103104
- name: Retrieve Keys
104105
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'deploy' }}
@@ -190,4 +191,4 @@ jobs:
190191
191192
- name: Cleanup the lab
192193
if: ${{ always() && (github.event_name == 'pull_request' || contains(fromJSON('["cleanup", "test"]'), github.event.inputs.mode)) }}
193-
run: scripts/hyperconverged-lab-uninstall.sh
194+
run: scripts/hyperconverged-lab-uninstall.sh kubespray

bin/install-neutron.sh

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -125,18 +125,9 @@ fi
125125
echo
126126

127127
# Set connection string based on whether we use Kube-OVN TLS
128-
# Hyperconverged build tries to execute the install script without yq in the
129-
# path
130-
function installYq() {
131-
export VERSION=v4.47.2
132-
export BINARY=yq_linux_amd64
133-
wget https://github.com/mikefarah/yq/releases/download/${VERSION}/${BINARY}.tar.gz -q -O - | tar xz && mv ${BINARY} /usr/local/bin/yq
134-
}
135-
136-
if ! yq --version 2> /dev/null; then
137-
echo "yq is not installed. Attempting to install yq"
138-
installYq
139-
fi
128+
# Source functions library for ensureYq
129+
source "${GENESTACK_BASE_DIR}/scripts/lib/functions.sh"
130+
ensureYq
140131

141132
if helm -n kube-system get values kube-ovn \
142133
| yq -e '.networking.ENABLE_SSL == true' >/dev/null 2>&1

bin/install-octavia.sh

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -124,18 +124,9 @@ fi
124124
echo
125125

126126
# Set connection string based on whether we use Kube-OVN TLS
127-
# Hyperconverged build tries to execute the install script without yq in the
128-
# path
129-
function installYq() {
130-
export VERSION=v4.47.2
131-
export BINARY=yq_linux_amd64
132-
wget https://github.com/mikefarah/yq/releases/download/${VERSION}/${BINARY}.tar.gz -q -O - | tar xz && mv ${BINARY} /usr/local/bin/yq
133-
}
134-
135-
if ! yq --version 2> /dev/null; then
136-
echo "yq is not installed. Attempting to install yq"
137-
installYq
138-
fi
127+
# Source functions library for ensureYq
128+
source "${GENESTACK_BASE_DIR}/scripts/lib/functions.sh"
129+
ensureYq
139130

140131
if helm -n kube-system get values kube-ovn \
141132
| yq -e '.networking.ENABLE_SSL == true' >/dev/null 2>&1

bin/setup-openstack-rc.sh

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
11
#!/usr/bin/env bash
22
set -e
33

4-
function installYq() {
5-
export VERSION=v4.47.2
6-
export BINARY=yq_linux_amd64
7-
wget https://github.com/mikefarah/yq/releases/download/${VERSION}/${BINARY}.tar.gz -q -O - | tar xz && mv ${BINARY} /usr/local/bin/yq
8-
}
9-
10-
if ! yq --version 2> /dev/null; then
11-
echo "yq is not installed. Attempting to install yq"
12-
installYq
13-
fi
4+
# Base directories provided by the environment
5+
GENESTACK_BASE_DIR="${GENESTACK_BASE_DIR:-/opt/genestack}"
6+
7+
# Source functions library for ensureYq
8+
source "${GENESTACK_BASE_DIR}/scripts/lib/functions.sh"
149

1510
USER_NAME="$(whoami)"
1611
USER_PATH="$(getent passwd ${USER_NAME} | awk -F':' '{print $6}')"
@@ -19,6 +14,8 @@ CONFIG_FILE="${CONFIG_PATH}/genestack-clouds.yaml"
1914

2015
mkdir -p "${CONFIG_PATH}"
2116

17+
echo "Generating OpenStack RC file at: ${CONFIG_FILE}"
18+
2219
cat > "${CONFIG_FILE}" <<EOF
2320
cache:
2421
auth: true
@@ -39,6 +36,7 @@ clouds:
3936
EOF
4037

4138
if [ -f "${CONFIG_PATH}/clouds.yaml" ]; then
39+
ensureYq
4240
/usr/local/bin/yq eval-all 'select(filename == "'"${CONFIG_PATH}/clouds.yaml"'") * select(filename == "'"${CONFIG_FILE}"'")' \
4341
"${CONFIG_FILE}" \
4442
"${CONFIG_PATH}/clouds.yaml" | tee "${CONFIG_PATH}/clouds.yaml.tmp"

openstack-components.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
---
2+
# This file is used to determine which services will be installed automatically
3+
# via the hyperconverged lab and in a future release the genestack-installed.
24
components:
35
keystone: true
46
glance: true
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#!/usr/bin/env bash
2+
# shellcheck disable=SC2124,SC2145,SC2294,SC2086,SC2087,SC2155
3+
#
4+
# Hyperconverged Lab Uninstall Script for Kubespray
5+
#
6+
# This script removes all resources created by the Kubespray hyperconverged lab script.
7+
#
8+
9+
set -o pipefail
10+
set -e
11+
SECONDS=0
12+
13+
# Source common uninstall library
14+
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)
15+
source "${SCRIPT_DIR}/lib/hyperconverged-uninstall-common.sh"
16+
17+
#############################################################################
18+
# Initialize
19+
#############################################################################
20+
21+
promptForCloudConfig
22+
23+
export LAB_NAME_PREFIX="${LAB_NAME_PREFIX:-hyperconverged}"
24+
25+
#############################################################################
26+
# Run Common Uninstall
27+
#############################################################################
28+
29+
runCommonUninstall "${LAB_NAME_PREFIX}"
30+
31+
#############################################################################
32+
# Kubespray-Specific: Delete SSH Keypair and Security Group
33+
#############################################################################
34+
35+
echo "Deleting Kubespray-specific resources..."
36+
keypairDelete ${LAB_NAME_PREFIX}-key
37+
securityGroupDelete ${LAB_NAME_PREFIX}-jump-secgroup
38+
39+
#############################################################################
40+
# Cleanup Complete
41+
#############################################################################
42+
43+
echo "Cleanup complete"
44+
echo "The Kubespray lab uninstall took ${SECONDS} seconds to complete."
45+
echo ""
46+
echo "Note: Local SSH key files (~/.ssh/${LAB_NAME_PREFIX}-key.pem, ~/.ssh/${LAB_NAME_PREFIX}-key.pub)"
47+
echo "were NOT removed. Delete them manually if no longer needed."

0 commit comments

Comments
 (0)