Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
205 changes: 195 additions & 10 deletions .github/workflows/omni-template-sync.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,33 @@ on:
paths:
- "turing/template.yaml"
- "turing/patches/**"
- "turing/helmfile.yaml"
- "turing/helm/**"
- "mocha/template.yaml"
- "mocha/patches/**"
- "mocha/helmfile.yaml"
- "mocha/helm/**"
pull_request:
branches:
- main
paths:
- "turing/template.yaml"
- "turing/patches/**"
- "turing/helmfile.yaml"
- "turing/helm/**"
- "mocha/template.yaml"
- "mocha/patches/**"
- "mocha/helmfile.yaml"
- "mocha/helm/**"

permissions:
contents: read
pull-requests: write

jobs:
# ----------------------------------------------------------------
# Detect which clusters were actually touched in this push.
# Detect which clusters were actually touched in this push/PR.
# Watches both Omni template files and Helm files.
# Outputs a JSON array, e.g. ["turing"] or ["mocha"] or ["turing","mocha"].
# ----------------------------------------------------------------
detect:
Expand All @@ -25,14 +43,19 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2 # need HEAD~1 to diff against
fetch-depth: 0 # full history needed for PR base-branch diff

- name: Detect changed clusters
id: detect
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
range="origin/${{ github.base_ref }}...${{ github.sha }}"
else
range="HEAD~1..HEAD"
fi
clusters=$(
git diff --name-only HEAD~1 HEAD \
| grep -E '^(turing|mocha)/(template\.yaml|patches/)' \
git diff --name-only $range \
| grep -E '^(turing|mocha)/(template\.yaml|patches/|helmfile\.yaml|helm/)' \
| cut -d/ -f1 \
| sort -u \
| jq -Rsc 'split("\n") | map(select(length > 0))'
Expand All @@ -41,12 +64,148 @@ jobs:
echo "Clusters to sync: ${clusters}"

# ----------------------------------------------------------------
# Sync each changed cluster in parallel via matrix.
# Skipped entirely if no relevant cluster changed.
# Dry-run on PRs:
# 1. omnictl cluster template sync --dry-run
# 2. helmfile diff
# Both results posted as a single PR comment per cluster.
# ----------------------------------------------------------------
dry-run:
needs: detect
if: github.event_name == 'pull_request' && needs.detect.outputs.clusters != '[]'
runs-on: ubuntu-latest
strategy:
matrix:
cluster: ${{ fromJson(needs.detect.outputs.clusters) }}
fail-fast: false

name: Dry-run ${{ matrix.cluster }}
steps:
- uses: actions/checkout@v4

- name: Install omnictl
run: |
curl -sSL -o omnictl \
https://github.com/siderolabs/omni/releases/download/v1.7.1/omnictl-linux-amd64
chmod +x omnictl && sudo mv omnictl /usr/local/bin/omnictl

- uses: azure/setup-helm@v4
with:
version: '3.17.0'

- name: Install helmfile + helm-diff plugin
run: |
curl -fsSL \
https://github.com/helmfile/helmfile/releases/download/v0.171.0/helmfile_0.171.0_linux_amd64.tar.gz \
| tar xz -C /tmp helmfile
sudo mv /tmp/helmfile /usr/local/bin/helmfile
# Pin to v3.9.4 — pre-dates the platformHooks field that breaks older Helm parsers
helm plugin install https://github.com/databus23/helm-diff --version v3.9.4

- name: omnictl dry-run — ${{ matrix.cluster }}
id: omni-dry-run
continue-on-error: true
working-directory: ${{ matrix.cluster }}
env:
OMNI_ENDPOINT: ${{ secrets.OMNI_ENDPOINT }}
OMNI_SERVICE_ACCOUNT_KEY: ${{ secrets.OMNI_SERVICE_ACCOUNT_KEY }}
run: |
omnictl cluster template sync -f template.yaml -d \
> /tmp/omni-dry-run.txt 2>&1

- name: helmfile diff — ${{ matrix.cluster }}
id: helm-diff
continue-on-error: true
working-directory: ${{ matrix.cluster }}
env:
OMNI_ENDPOINT: ${{ secrets.OMNI_ENDPOINT }}
OMNI_SERVICE_ACCOUNT_KEY: ${{ secrets.OMNI_SERVICE_ACCOUNT_KEY }}
run: |
if [ ! -f helmfile.yaml ]; then
echo "(no helmfile.yaml — helm not managed for this cluster yet)" \
> /tmp/helm-diff.txt
exit 0
fi
# --service-account generates a static bearer-token kubeconfig (no oidc-login needed in CI)
omnictl kubeconfig --service-account --cluster ${{ matrix.cluster }} --user ci \
/tmp/${{ matrix.cluster }}.kubeconfig
KUBECONFIG=/tmp/${{ matrix.cluster }}.kubeconfig \
helmfile diff --no-color 2>&1 \
| tee /tmp/helm-diff.txt

- name: Post dry-run result as PR comment
if: always()
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const cluster = '${{ matrix.cluster }}';

const omniOk = '${{ steps.omni-dry-run.outcome }}' === 'success';
const helmOk = '${{ steps.helm-diff.outcome }}' === 'success';

const omniOut = fs.existsSync('/tmp/omni-dry-run.txt')
? fs.readFileSync('/tmp/omni-dry-run.txt', 'utf8').trim()
: '(file not found)';
const helmOut = fs.existsSync('/tmp/helm-diff.txt')
? fs.readFileSync('/tmp/helm-diff.txt', 'utf8').trim()
: '(file not found)';

const s = (ok) => ok ? '✅' : '❌';
const marker = `<!-- omnictl-dry-run-${cluster} -->`;

const body = [
marker,
`## ${s(omniOk && helmOk)} Dry-run — \`${cluster}\``,
'',
`### ${s(omniOk)} \`omnictl\` template sync`,
'```',
omniOut || '(no output)',
'```',
'',
`### ${s(helmOk)} \`helmfile diff\``,
'```diff',
helmOut || '(no output)',
'```',
'',
`> commit \`${{ github.sha }}\``,
].join('\n');

const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const existing = comments.find(c => c.body.includes(marker));
if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body,
});
}

- name: Fail job if any dry-run step failed
if: steps.omni-dry-run.outcome == 'failure' || steps.helm-diff.outcome == 'failure'
run: |
echo "One or more dry-run steps failed. See the PR comment for details."
exit 1

# ----------------------------------------------------------------
# Sync on push to main:
# 1. omnictl cluster template sync
# 2. helmfile apply
# ----------------------------------------------------------------
sync:
needs: detect
if: needs.detect.outputs.clusters != '[]'
if: github.event_name == 'push' && needs.detect.outputs.clusters != '[]'
runs-on: ubuntu-latest
strategy:
matrix:
Expand All @@ -57,16 +216,42 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Install omnictl v1.7.1
- name: Install tools (omnictl, helm, helmfile)
run: |
# omnictl
curl -sSL -o omnictl \
https://github.com/siderolabs/omni/releases/download/v1.7.1/omnictl-linux-amd64
chmod +x omnictl
sudo mv omnictl /usr/local/bin/omnictl
chmod +x omnictl && sudo mv omnictl /usr/local/bin/omnictl

- uses: azure/setup-helm@v4
with:
version: '3.17.0'

- name: Install helmfile + helm-diff plugin
run: |
curl -fsSL \
https://github.com/helmfile/helmfile/releases/download/v0.171.0/helmfile_0.171.0_linux_amd64.tar.gz \
| tar xz -C /tmp helmfile
sudo mv /tmp/helmfile /usr/local/bin/helmfile
# Pin to v3.9.4 — pre-dates the platformHooks field that breaks older Helm parsers
helm plugin install https://github.com/databus23/helm-diff --version v3.9.4

- name: Sync ${{ matrix.cluster }} cluster template
working-directory: ${{ matrix.cluster }}
env:
OMNI_ENDPOINT: ${{ secrets.OMNI_ENDPOINT }}
OMNI_SERVICE_ACCOUNT_KEY: ${{ secrets.OMNI_SERVICE_ACCOUNT_KEY }}
run: omnictl cluster template sync -f template.yaml

- name: helmfile apply — ${{ matrix.cluster }}
working-directory: ${{ matrix.cluster }}
env:
OMNI_ENDPOINT: ${{ secrets.OMNI_ENDPOINT }}
OMNI_SERVICE_ACCOUNT_KEY: ${{ secrets.OMNI_SERVICE_ACCOUNT_KEY }}
run: |
# Skip clusters that don't have a helmfile yet
[ -f helmfile.yaml ] || { echo "No helmfile.yaml — skipping helm apply"; exit 0; }
# --service-account generates a static bearer-token kubeconfig (no oidc-login needed in CI)
omnictl kubeconfig --service-account --cluster ${{ matrix.cluster }} --user ci \
/tmp/${{ matrix.cluster }}.kubeconfig
KUBECONFIG=/tmp/${{ matrix.cluster }}.kubeconfig helmfile apply
45 changes: 45 additions & 0 deletions turing/helm/cilium/values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Cilium values — turing cluster (Turing Pi, home lab)
# Applied via: helmfile apply (CI) or helmfile diff (PR dry-run)

# Kube-proxy is disabled in Talos (patches/disable-kubeproxy.yml);
# Cilium handles all service routing through eBPF.
kubeProxyReplacement: true

# VXLAN tunnel — nodes are on different L2 segments (KubeSpan WireGuard overlay)
routingMode: tunnel
tunnelProtocol: vxlan
autoDirectNodeRoutes: false

bpf:
masquerade: true

ipam:
mode: kubernetes

ipv6:
enabled: false

# L2 announcements — exposes LoadBalancer IPs on the LAN (pool: 192.168.1.200-250)
l2announcements:
enabled: true
leaseDuration: 3s
leaseRenewDeadline: 1s
leaseRetryPeriod: 200ms

externalIPs:
enabled: true

operator:
# 3 control-plane nodes — keep 1 replica (bumping to 2 is safe but unnecessary)
replicas: 1

hubble:
enabled: true
tls:
auto:
method: helm
certValidityDuration: 1095 # 3 years
relay:
enabled: true
ui:
enabled: false
11 changes: 11 additions & 0 deletions turing/helmfile.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
repositories:
- name: cilium
url: https://helm.cilium.io/

releases:
- name: cilium
namespace: kube-system
chart: cilium/cilium
version: "1.18.2"
values:
- helm/cilium/values.yaml
4 changes: 2 additions & 2 deletions turing/patches/extraManifests.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
cluster:
extraManifests:
# --- Cilium Installation ---
- https://raw.githubusercontent.com/qjoly/gitops/refs/heads/main/common/cilium/install-cilium.yaml
- https://raw.githubusercontent.com/qjoly/gitops/refs/heads/main/common/cilium/L2Announcement.yaml
# - https://raw.githubusercontent.com/qjoly/gitops/refs/heads/main/common/cilium/install-cilium.yaml
# - https://raw.githubusercontent.com/qjoly/gitops/refs/heads/main/common/cilium/L2Announcement.yaml
# --- ArgoCD Installation ---
- https://raw.githubusercontent.com/qjoly/gitops/refs/heads/main/common/argocd/argocd.namespace.yaml
- https://raw.githubusercontent.com/qjoly/gitops/refs/heads/main/common/argocd/argocd.install.yaml
Expand Down
2 changes: 1 addition & 1 deletion turing/template.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
kind: Cluster
name: turing # Turing Pi
kubernetes:
version: v1.35.1
version: v1.35.2
talos:
version: v1.13.0
features:
Expand Down
Loading