Skip to content

Commit 98c10dd

Browse files
committed
nat64_appliance image workflow
Add a workflow to build the nat64_appliance on a weekely schedule and create a uniq release and update the "latest" tag. Depends-On: openstack-k8s-operators/ci-framework#3550 Assisted-By: Claude Code/claude-4.5-sonnet Signed-off-by: Harald Jensås <hjensas@redhat.com>
1 parent 77556a4 commit 98c10dd

File tree

1 file changed

+257
-0
lines changed

1 file changed

+257
-0
lines changed
Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
name: Build NAT64 Appliance Image
2+
3+
on:
4+
# Allows you to run this workflow manually from the Actions tab
5+
workflow_dispatch:
6+
inputs:
7+
release_tag:
8+
description: 'Release tag (e.g., v1.0.0)'
9+
required: true
10+
ci_framework_repo:
11+
description: 'ci-framework repository (for testing forks)'
12+
required: false
13+
default: 'https://github.com/openstack-k8s-operators/ci-framework.git'
14+
ci_framework_ref:
15+
description: 'ci-framework branch/tag/PR (e.g., main, my-branch, refs/pull/123/head)'
16+
required: false
17+
default: 'main'
18+
19+
# Run weekly on Mondays at 00:00 UTC
20+
schedule:
21+
- cron: '0 0 * * 1'
22+
23+
jobs:
24+
build-image:
25+
runs-on: ubuntu-22.04
26+
27+
# Permission needed to create a release and upload assets
28+
permissions:
29+
contents: write
30+
31+
env:
32+
WORK_DIR: ${{ github.workspace }}/ci-framework-data
33+
34+
steps:
35+
- name: 1. Install System Dependencies
36+
run: |
37+
echo "Installing system dependencies for diskimage-builder..."
38+
sudo apt-get update
39+
sudo apt-get install -y \
40+
python3-pip \
41+
python3-venv \
42+
qemu-utils \
43+
dosfstools \
44+
xfsprogs \
45+
kpartx \
46+
debootstrap \
47+
gdisk \
48+
git
49+
echo "System dependencies installed"
50+
51+
- name: 2. Clone ci-framework Repository
52+
run: |
53+
CI_REPO="${{ inputs.ci_framework_repo || 'https://github.com/openstack-k8s-operators/ci-framework.git' }}"
54+
CI_REF="${{ inputs.ci_framework_ref || 'main' }}"
55+
56+
echo "Cloning ci-framework..."
57+
echo " Repository: $CI_REPO"
58+
echo " Reference: $CI_REF"
59+
60+
# Check if this is a special ref (like refs/pull/123/head)
61+
if [[ "$CI_REF" == refs/* ]]; then
62+
echo "Detected special ref, using fetch method..."
63+
git clone "$CI_REPO" ${{ github.workspace }}/ci-framework
64+
cd ${{ github.workspace }}/ci-framework
65+
git fetch origin "$CI_REF"
66+
git checkout FETCH_HEAD
67+
else
68+
echo "Detected branch/tag, using direct clone with shallow history..."
69+
git clone --depth 1 --branch "$CI_REF" "$CI_REPO" \
70+
${{ github.workspace }}/ci-framework
71+
fi
72+
73+
echo "ci-framework cloned successfully"
74+
cd ${{ github.workspace }}/ci-framework
75+
echo "Current commit: $(git rev-parse HEAD)"
76+
echo "Current branch/ref: $(git describe --all)"
77+
78+
- name: 3. Setup Python Virtual Environment
79+
run: |
80+
echo "Creating Python virtual environment at ~/nat64_venv..."
81+
python3 -m venv ~/nat64_venv
82+
source ~/nat64_venv/bin/activate
83+
84+
pip install --upgrade pip setuptools wheel
85+
86+
echo "Installing Ansible and diskimage-builder..."
87+
pip install ansible-core
88+
pip install diskimage-builder
89+
90+
echo "Environment setup complete"
91+
92+
- name: 4. Create Ansible Playbook for Building NAT64 Image
93+
run: |
94+
cat > ${{ github.workspace }}/build-nat64.yml << 'EOF'
95+
---
96+
- name: Build nat64-appliance image
97+
hosts: localhost
98+
connection: local
99+
gather_facts: true
100+
vars:
101+
cifmw_basedir: "${{ env.WORK_DIR }}"
102+
cifmw_nat64_appliance_run_dib_as_root: false
103+
cifmw_nat64_appliance_use_ci_script: false
104+
cifmw_nat64_appliance_venv_dir: "{{ ansible_env.HOME }}/nat64_venv"
105+
roles:
106+
- nat64_appliance
107+
EOF
108+
109+
echo "Ansible playbook created"
110+
cat ${{ github.workspace }}/build-nat64.yml
111+
112+
- name: 5. Run Ansible Playbook to Build Image
113+
run: |
114+
echo "Building NAT64 appliance image using Ansible..."
115+
echo "Using ci-framework role defaults for DIB configuration"
116+
echo "Skipping package installation (already done in step 3)"
117+
118+
cd ${{ github.workspace }}/ci-framework
119+
120+
# Activate the venv and run the playbook
121+
source ~/nat64_venv/bin/activate
122+
123+
# Skip 'packages' tag since we already installed dependencies
124+
# Use our venv at ~/nat64_venv instead of letting role create one
125+
ANSIBLE_ROLES_PATH=${{ github.workspace }}/ci-framework/roles \
126+
ansible-playbook -v \
127+
--skip-tags packages \
128+
${{ github.workspace }}/build-nat64.yml
129+
130+
echo "Image build completed successfully"
131+
132+
- name: 6. Verify Built Image
133+
run: |
134+
IMAGE_PATH="${{ env.WORK_DIR }}/nat64_appliance/nat64-appliance.qcow2"
135+
136+
if [ -f "$IMAGE_PATH" ]; then
137+
echo "Built image details:"
138+
ls -lh "$IMAGE_PATH"
139+
qemu-img info "$IMAGE_PATH"
140+
else
141+
echo "ERROR: Image file not found at $IMAGE_PATH"
142+
echo "Checking work directory contents:"
143+
ls -laR "${{ env.WORK_DIR }}"
144+
exit 1
145+
fi
146+
147+
- name: 7. Create Unique Release Tag and Rename Image
148+
id: release_tag
149+
run: |
150+
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
151+
# Manual run: use provided tag
152+
RELEASE_TAG="${{ inputs.release_tag }}"
153+
else
154+
# Scheduled run: generate timestamp-based tag
155+
RELEASE_TAG="build-$(date +%Y%m%d-%H%M%S)"
156+
fi
157+
158+
echo "release_tag=$RELEASE_TAG" >> $GITHUB_OUTPUT
159+
echo "Release tag: $RELEASE_TAG"
160+
161+
# Rename image to include the release tag
162+
TAGGED_IMAGE="nat64-appliance-${RELEASE_TAG}.qcow2"
163+
mv ${{ env.WORK_DIR }}/nat64_appliance/nat64-appliance.qcow2 \
164+
${{ github.workspace }}/${TAGGED_IMAGE}
165+
166+
echo "tagged_image=$TAGGED_IMAGE" >> $GITHUB_OUTPUT
167+
echo "Image renamed to: $TAGGED_IMAGE"
168+
ls -lh ${{ github.workspace }}/${TAGGED_IMAGE}
169+
170+
- name: 8. Create Versioned GitHub Release
171+
uses: softprops/action-gh-release@v2
172+
with:
173+
tag_name: ${{ steps.release_tag.outputs.release_tag }}
174+
name: "NAT64 Appliance ${{ steps.release_tag.outputs.release_tag }}"
175+
body: |
176+
NAT64 Appliance image built by GitHub Actions.
177+
178+
## Build Configuration
179+
180+
- **ci-framework repository**: `${{ inputs.ci_framework_repo || 'https://github.com/openstack-k8s-operators/ci-framework.git' }}`
181+
- **ci-framework reference**: `${{ inputs.ci_framework_ref || 'main' }}`
182+
- **Build type**: ${{ github.event_name == 'schedule' && 'Scheduled (weekly)' || 'Manual dispatch' }}
183+
184+
DIB configuration uses defaults from the ci-framework nat64_appliance role.
185+
186+
## Usage
187+
188+
For usage instructions and deployment examples, see the
189+
[nat64_appliance README](https://github.com/openstack-k8s-operators/ci-framework/blob/main/roles/nat64_appliance/README.md).
190+
files: ${{ steps.release_tag.outputs.tagged_image }}
191+
192+
- name: 9. Update 'latest' Release Tag
193+
uses: softprops/action-gh-release@v2
194+
with:
195+
tag_name: latest
196+
name: "NAT64 Appliance (Latest)"
197+
prerelease: true
198+
body: |
199+
This is the latest NAT64 Appliance build. This release is automatically updated.
200+
201+
**Latest Build**: ${{ steps.release_tag.outputs.release_tag }}
202+
203+
## Download
204+
205+
Use the static URL for the latest build:
206+
```bash
207+
curl -L -O https://github.com/openstack-k8s-operators/openstack-k8s-operators-ci/releases/download/latest/nat64-appliance-latest.qcow2
208+
```
209+
210+
Or download a specific version from the [releases page](https://github.com/openstack-k8s-operators/openstack-k8s-operators-ci/releases)
211+
to pin your CI to a known-good build.
212+
213+
## Usage
214+
215+
For usage instructions and deployment examples, see the
216+
[nat64_appliance README](https://github.com/openstack-k8s-operators/ci-framework/blob/main/roles/nat64_appliance/README.md).
217+
files: ${{ steps.release_tag.outputs.tagged_image }}
218+
219+
- name: 10. Upload Image with Static Filename to Latest Release
220+
run: |
221+
echo "Creating static filename copy for easy downloading..."
222+
223+
# Copy the image with a static name
224+
cp ${{ github.workspace }}/${{ steps.release_tag.outputs.tagged_image }} \
225+
${{ github.workspace }}/nat64-appliance-latest.qcow2
226+
227+
echo "Uploading to latest release with static filename..."
228+
# Upload to latest release, replacing any existing file with the same name
229+
gh release upload latest nat64-appliance-latest.qcow2 --clobber
230+
231+
echo "Static URL available at:"
232+
echo "https://github.com/${{ github.repository }}/releases/download/latest/nat64-appliance-latest.qcow2"
233+
env:
234+
GH_TOKEN: ${{ github.token }}
235+
236+
- name: 11. Cleanup Old Releases (Keep Last 4)
237+
if: github.event_name == 'schedule'
238+
run: |
239+
echo "Cleaning up old scheduled builds, keeping last 4..."
240+
241+
# Get all releases with 'build-' prefix, sort by creation date (newest first)
242+
# Skip the first 4 (keep them), delete the rest
243+
OLD_RELEASES=$(gh release list --limit 100 --json tagName,createdAt \
244+
| jq -r '.[] | select(.tagName | startswith("build-")) | .tagName' \
245+
| sort -r \
246+
| tail -n +5)
247+
248+
if [ -n "$OLD_RELEASES" ]; then
249+
echo "Deleting old releases:"
250+
echo "$OLD_RELEASES"
251+
echo "$OLD_RELEASES" | xargs -I {} gh release delete {} --yes --cleanup-tag
252+
echo "Cleanup complete"
253+
else
254+
echo "No old releases to delete (fewer than 5 total)"
255+
fi
256+
env:
257+
GH_TOKEN: ${{ github.token }}

0 commit comments

Comments
 (0)