Skip to content

Commit af4753c

Browse files
committed
Expand release workflow manifest gen
1 parent 4fd1f5f commit af4753c

File tree

4 files changed

+189
-12
lines changed

4 files changed

+189
-12
lines changed

.github/workflows/release.yml

Lines changed: 121 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ jobs:
197197
password: ${{ secrets.DOCKERHUB_TOKEN }}
198198

199199
- name: Build and push Docker image
200+
id: build
200201
uses: docker/build-push-action@v5
201202
with:
202203
context: .
@@ -211,6 +212,24 @@ jobs:
211212
cache-from: type=gha,scope=${{ matrix.webapp.name }}
212213
cache-to: type=gha,mode=max,scope=${{ matrix.webapp.name }}
213214

215+
- name: Write digest artifact
216+
run: |
217+
mkdir -p dist
218+
cat > dist/image-${{ matrix.webapp.name }}.json <<JSON
219+
{
220+
"name": "${{ matrix.webapp.name }}",
221+
"image": "${{ env.REGISTRY }}/frameworks-${{ matrix.webapp.name }}:${{ github.ref_name }}",
222+
"digest": "${{ steps.build.outputs.digest }}",
223+
"git_commit": "${{ github.sha }}"
224+
}
225+
JSON
226+
227+
- name: Upload digest artifact
228+
uses: actions/upload-artifact@v4
229+
with:
230+
name: image-digest-${{ matrix.webapp.name }}
231+
path: dist/image-${{ matrix.webapp.name }}.json
232+
214233
- name: Upload static bundle artifact
215234
uses: actions/upload-artifact@v4
216235
with:
@@ -277,22 +296,110 @@ jobs:
277296
pattern: image-digest-*
278297
path: dist/digests
279298
merge-multiple: true
299+
300+
- name: Fetch MistServer digest from GHCR
301+
id: mistserver
302+
env:
303+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
304+
run: |
305+
set -euo pipefail
306+
307+
# Query GHCR API for latest MistServer digest
308+
DIGEST=$(curl -sL \
309+
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
310+
-H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
311+
"https://ghcr.io/v2/livepeer-frameworks/mistserver/manifests/latest" \
312+
| jq -r '.config.digest // empty')
313+
314+
if [[ -z "$DIGEST" ]]; then
315+
echo "WARNING: Could not fetch MistServer digest from GHCR, using placeholder"
316+
DIGEST="sha256:TODO-fetch-failed"
317+
fi
318+
319+
echo "digest=${DIGEST}" >> "$GITHUB_OUTPUT"
320+
echo "Fetched MistServer digest: ${DIGEST}"
321+
280322
- name: Generate manifest
281323
run: |
282-
echo "platform_version: ${{ github.ref_name }}" > dist/manifest.yaml
283-
echo "git_commit: ${{ github.sha }}" >> dist/manifest.yaml
284-
echo "release_date: $(date -u '+%Y-%m-%dT%H:%M:%SZ')" >> dist/manifest.yaml
324+
set -euo pipefail
325+
326+
# Header
327+
cat > dist/manifest.yaml <<YAML
328+
platform_version: ${{ github.ref_name }}
329+
git_commit: ${{ github.sha }}
330+
release_date: $(date -u '+%Y-%m-%dT%H:%M:%SZ')
331+
332+
YAML
333+
334+
# Services (microservices with service_version field)
285335
echo "services:" >> dist/manifest.yaml
286336
for f in dist/digests/*.json; do
287337
name=$(jq -r .name "$f")
338+
# Skip webapp/website - they go in interfaces section
339+
if [[ "$name" == "webapp" || "$name" == "website" ]]; then
340+
continue
341+
fi
342+
288343
image=$(jq -r .image "$f")
289344
digest=$(jq -r .digest "$f")
290345
svcver=$(jq -r .service_version "$f")
291-
echo " - name: ${name}" >> dist/manifest.yaml
292-
echo " service_version: ${svcver}" >> dist/manifest.yaml
293-
echo " image: ${image}" >> dist/manifest.yaml
294-
echo " digest: ${digest}" >> dist/manifest.yaml
346+
347+
cat >> dist/manifest.yaml <<YAML
348+
- name: ${name}
349+
service_version: ${svcver}
350+
image: ${image}
351+
digest: ${digest}
352+
YAML
295353
done
354+
355+
# Interfaces (webapp/website reference implementations)
356+
echo "" >> dist/manifest.yaml
357+
echo "interfaces:" >> dist/manifest.yaml
358+
for f in dist/digests/*.json; do
359+
name=$(jq -r .name "$f")
360+
# Only include webapp/website
361+
if [[ "$name" != "webapp" && "$name" != "website" ]]; then
362+
continue
363+
fi
364+
365+
image=$(jq -r .image "$f")
366+
digest=$(jq -r .digest "$f")
367+
368+
# Determine build dir and bundle name
369+
if [[ "$name" == "webapp" ]]; then
370+
bundle="webapp-build.tar.gz"
371+
else
372+
bundle="website-build.tar.gz"
373+
fi
374+
375+
cat >> dist/manifest.yaml <<YAML
376+
- name: ${name}
377+
type: reference-implementation
378+
deployment_options: [docker, systemd]
379+
image: ${image}
380+
digest: ${digest}
381+
static_bundle: ${bundle}
382+
note: "White-label example - fork and customize for production deployments"
383+
YAML
384+
done
385+
386+
# External Dependencies (MistServer from separate repo)
387+
echo "" >> dist/manifest.yaml
388+
cat >> dist/manifest.yaml <<YAML
389+
external_dependencies:
390+
- name: mistserver
391+
repository: github.com/Livepeer-FrameWorks/mistserver
392+
image: ghcr.io/livepeer-frameworks/mistserver:latest
393+
digest: "${{ steps.mistserver.outputs.digest }}"
394+
compatibility_level: backwards-compatible
395+
required_by: [helmsman]
396+
deployment_options: [native-preferred, docker]
397+
note: "Built from separate fork - pinning optional due to backwards compatibility"
398+
YAML
399+
400+
# Infrastructure Requirements (from config/infrastructure.yaml)
401+
echo "" >> dist/manifest.yaml
402+
cat config/infrastructure.yaml >> dist/manifest.yaml
296403
- name: Upload manifest artifact
297404
uses: actions/upload-artifact@v4
298405
with:
@@ -369,10 +476,15 @@ jobs:
369476
# Commit and push
370477
git config user.name "github-actions"
371478
git config user.email "[email protected]"
372-
git checkout -b "${RELEASE_BRANCH}"
479+
480+
# Fetch branch if it exists
481+
git fetch origin "${RELEASE_BRANCH}" || true
482+
483+
# Create or reset to new content
484+
git checkout -B "${RELEASE_BRANCH}"
373485
git add releases/${{ github.ref_name }}.yaml channels/${channel}.yaml
374486
git commit -m "Release manifest for ${{ github.ref_name }}"
375-
git push origin "${RELEASE_BRANCH}"
487+
git push --force origin "${RELEASE_BRANCH}"
376488
377489
- name: Create PR to env repo
378490
env:

config/infrastructure.yaml

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Infrastructure Requirements for FrameWorks Platform
2+
# This file tracks tested infrastructure versions for each platform release
3+
# Update manually when bumping infrastructure components
4+
5+
infrastructure:
6+
- name: postgresql
7+
tested_version: "15.14"
8+
minimum_version: "14.0"
9+
image: postgres:15
10+
dev_version: "15.14"
11+
prod_version: "15.12-YB-2025.1.0.0"
12+
notes: "Dev uses PostgreSQL 15.14. Prod uses YugabyteDB (PostgreSQL 15.12 compatible)"
13+
14+
- name: kafka
15+
tested_version: "7.4.0"
16+
minimum_version: "3.4.0"
17+
image: confluentinc/cp-kafka:7.4.0
18+
dev_version: "7.4.0 (Confluent Platform)"
19+
prod_version: "3.9.1"
20+
notes: "Dev uses Confluent Platform 7.4.0. Prod uses Apache Kafka 3.9.1"
21+
22+
- name: zookeeper
23+
tested_version: "7.4.0"
24+
minimum_version: "3.4.0"
25+
image: confluentinc/cp-zookeeper:7.4.0
26+
notes: "Required for Kafka. Confluent Platform includes Zookeeper"
27+
28+
- name: clickhouse
29+
tested_version: "25.9.2.1"
30+
minimum_version: "18.16.1"
31+
image: clickhouse/clickhouse-server:latest
32+
dev_version: "25.9.2.1"
33+
prod_version: "18.16.1"
34+
notes: "WARNING: Dev (25.9.2.1) and Prod (18.16.1) have significant version gap. Consider upgrading prod"
35+
36+
- name: prometheus
37+
tested_version: "3.6.0"
38+
minimum_version: "2.40.0"
39+
image: prom/prometheus:latest
40+
dev_version: "3.6.0"
41+
prod_alternative: "VictoriaMetrics v1.122.0"
42+
notes: "Dev uses Prometheus 3.6.0. Prod uses VictoriaMetrics v1.122.0 (Prometheus-compatible)"
43+
44+
- name: victoriametrics
45+
tested_version: "v1.122.0"
46+
minimum_version: "v1.100.0"
47+
image: victoriametrics/victoria-metrics:latest
48+
prod_version: "v1.122.0"
49+
notes: "Production alternative to Prometheus. Prometheus-compatible API"
50+
51+
- name: grafana
52+
tested_version: "12.2.0"
53+
minimum_version: "11.0.0"
54+
image: grafana/grafana:latest
55+
dev_version: "12.2.0"
56+
prod_version: "11.6.1"
57+
notes: "Requires grafana-clickhouse-datasource plugin for ClickHouse integration"
58+
59+
- name: nginx
60+
tested_version: "1.29.3"
61+
minimum_version: "1.24.0"
62+
image: nginx:alpine
63+
dev_version: "1.29.3 (alpine)"
64+
prod_version: "1.29.1"
65+
notes: "Alpine variant for smaller footprint in dev/docker environments"

docker-compose.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ services:
120120
# MistServer with AV libs.
121121
# Note: MistServer requires significant shared memory for holding stream buffers.
122122
mistserver:
123-
image: ddvtech/mistserver_alpine_minimal:with_av
123+
image: livepeerframeworks/mistserver:latest
124124
container_name: frameworks-mistserver
125125
platform: linux/amd64
126126
shm_size: '2gb' # Allocate 2GB of shared memory for MistServer
@@ -138,7 +138,7 @@ services:
138138
- ./infrastructure/mistserver.conf:/etc/mistserver.conf
139139
- mistserver_data:/var/lib/mistserver
140140
restart: unless-stopped
141-
command: ["/usr/bin/MistController", "-c", "/etc/mistserver.conf"]
141+
command: ["MistController", "-c", "/etc/mistserver.conf"]
142142
networks:
143143
- frameworks
144144
ulimits:

infrastructure/mistserver.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"account":{"test":{"password":"098f6bcd4621d373cade4e832627b4f6"}},"auto_push":null,"autopushes":null,"bandwidth":{"exceptions":["::1","127.0.0.0/8","10.0.0.0/8","192.168.0.0/16","172.16.0.0/12"],"limit":62500000},"config":{"accesslog":"LOG","controller":{"interface":null,"port":null,"username":null},"debug":4,"defaultStream":null,"limits":null,"location":{"lat":52.1636000000,"lon":4.4802000000,"name":"Leiden"},"prometheus":"koekjes","protocols":[{"connector":"AAC"},{"connector":"CMAF"},{"connector":"DTSC"},{"connector":"EBML"},{"connector":"FLAC"},{"connector":"FLV"},{"connector":"H264"},{"connector":"HDS"},{"connector":"HLS"},{"connector":"HTTP","default_track_sorting":"id_lth","pubaddr":["http://localhost:18090/view/"]},{"connector":"HTTPTS"},{"connector":"JSON"},{"connector":"MP3"},{"connector":"MP4"},{"connector":"OGG"},{"connector":"RTMP"},{"connector":"RTSP"},{"connector":"SDP"},{"connector":"SubRip"},{"connector":"TSRIST"},{"connector":"TSSRT"},{"connector":"WAV"},{"bindhost":"0.0.0.0","connector":"WebRTC","default_track_sorting":"id_lth","jitterlog":false,"mergesessions":false,"nackdisable":false,"nolocal":false,"noresolve":false,"packetlog":false,"pubhost":"localhost:18090/view"},{"connector":"JPG"}],"serverid":null,"sessionInputMode":15,"sessionOutputMode":15,"sessionStreamInfoMode":"1","sessionUnspecifiedMode":0,"sessionViewerMode":14,"tknMode":15,"triggers":{"DEFAULT_STREAM":[{"handler":"http://helmsman:18007/webhooks/mist/default_stream","sync":true}],"LIVE_BANDWIDTH":[{"handler":"http://helmsman:18007/webhooks/mist/live_bandwidth","sync":false}],"LIVE_TRACK_LIST":[{"handler":"http://helmsman:18007/webhooks/mist/live_track_list","sync":false}],"PUSH_END":[{"handler":"http://helmsman:18007/webhooks/mist/push_end","sync":false}],"PUSH_OUT_START":[{"handler":"http://helmsman:18007/webhooks/mist/push_out_start","sync":true}],"PUSH_REWRITE":[{"handler":"http://helmsman:18007/webhooks/mist/push_rewrite","sync":true}],"RECORDING_END":[{"handler":"http://helmsman:18007/webhooks/mist/recording_end","sync":false}],"STREAM_BUFFER":[{"handler":"http://helmsman:18007/webhooks/mist/stream_buffer","sync":false}],"STREAM_END":[{"handler":"http://helmsman:18007/webhooks/mist/stream_end","sync":false}],"STREAM_SOURCE":[{"handler":"http://helmsman:18007/webhooks/mist/stream_source","sync":true}],"USER_END":[{"handler":"http://helmsman:18007/webhooks/mist/user_end","sync":false}],"USER_NEW":[{"default":"true","handler":"http://helmsman:18007/webhooks/mist/user_new","sync":true}]},"trustedproxy":[]},"extwriters":[["s3","livepeer-catalyst-uploader -t 2592000s",["s3","s3+http","s3+https","ipfs"]]],"push_settings":{"maxspeed":0,"wait":3},"streamkeys":null,"streams":{"live":{"debug":4,"name":"live","processes":[{"bitrate":120000,"codec":"opus","exit_unmask":false,"inconsequential":false,"process":"AV","restart_type":"fixed","track_inhibit":"audio=opus","track_select":"video=none","x-LSP-name":"Audio to Opus"},{"bitrate":120000000,"codec":"AAC","exit_unmask":false,"inconsequential":false,"process":"AV","restart_type":"fixed","track_inhibit":"audio=aac","track_select":"video=none","x-LSP-name":"Audio to AAC"}],"realtime":false,"source":"balance:http://foghorn:18008?fallback=push://","stop_sessions":false,"tags":[]},"live+$":{"name":"live+$","realtime":true,"source":"balance:http://foghorn:18008?fallback=push://","stop_sessions":false,"tags":["live"]},"vod":{"name":"vod","processes":[],"realtime":false,"source":"/tmp/none","stop_sessions":false,"tags":[]},"vod+$":{"name":"vod+$","realtime":false,"source":"balance:http://foghorn:18008?fallback=push://","stop_sessions":false,"tags":["vod"]}},"ui_settings":{"HTTPSUrl":"https://localhost:9090/view/","HTTPUrl":"http://localhost:8080/","sort_autopushes":{"by":"Stream","dir":1},"sort_pushes":{"by":"Statistics","dir":1},"sortstreams":{"by":"name","dir":1}},"variables":null}
1+
{"account":{"test":{"password":"098f6bcd4621d373cade4e832627b4f6"}},"auto_push":null,"autopushes":null,"bandwidth":{"exceptions":["::1","127.0.0.0/8","10.0.0.0/8","192.168.0.0/16","172.16.0.0/12"],"limit":62500000},"config":{"accesslog":"LOG","controller":{"interface":null,"port":null,"username":null},"debug":4,"defaultStream":null,"limits":null,"location":{"lat":52.1636,"lon":4.480200000000001,"name":"Leiden"},"prometheus":"koekjes","protocols":[{"connector":"AAC"},{"connector":"CMAF"},{"connector":"DTSC"},{"connector":"EBML"},{"connector":"FLAC"},{"connector":"FLV"},{"connector":"H264"},{"connector":"HDS"},{"connector":"HLS"},{"connector":"HTTP","default_track_sorting":"id_lth","pubaddr":["http://localhost:18090/view/"]},{"connector":"HTTPTS"},{"connector":"JSON"},{"connector":"MP3"},{"connector":"MP4"},{"connector":"OGG"},{"connector":"RTMP"},{"connector":"RTSP"},{"connector":"SDP"},{"connector":"SubRip"},{"connector":"TSRIST"},{"connector":"TSSRT"},{"connector":"WAV"},{"bindhost":"0.0.0.0","connector":"WebRTC","default_track_sorting":"id_lth","jitterlog":false,"mergesessions":false,"nackdisable":false,"nolocal":false,"noresolve":false,"packetlog":false,"pubhost":"localhost:18090/view"},{"connector":"JPG"}],"serverid":null,"sessionInputMode":15,"sessionOutputMode":15,"sessionStreamInfoMode":"1","sessionUnspecifiedMode":0,"sessionViewerMode":14,"tknMode":15,"triggers":{"DEFAULT_STREAM":[{"handler":"http://helmsman:18007/webhooks/mist/default_stream","sync":true}],"LIVE_BANDWIDTH":[{"handler":"http://helmsman:18007/webhooks/mist/live_bandwidth","sync":false}],"LIVE_TRACK_LIST":[{"handler":"http://helmsman:18007/webhooks/mist/live_track_list","sync":false}],"PUSH_END":[{"handler":"http://helmsman:18007/webhooks/mist/push_end","sync":false}],"PUSH_OUT_START":[{"handler":"http://helmsman:18007/webhooks/mist/push_out_start","sync":true}],"PUSH_REWRITE":[{"handler":"http://helmsman:18007/webhooks/mist/push_rewrite","sync":true}],"RECORDING_END":[{"handler":"http://helmsman:18007/webhooks/mist/recording_end","sync":false}],"STREAM_BUFFER":[{"handler":"http://helmsman:18007/webhooks/mist/stream_buffer","sync":false}],"STREAM_END":[{"handler":"http://helmsman:18007/webhooks/mist/stream_end","sync":false}],"STREAM_SOURCE":[{"handler":"http://helmsman:18007/webhooks/mist/stream_source","sync":true}],"USER_END":[{"handler":"http://helmsman:18007/webhooks/mist/user_end","sync":false}],"USER_NEW":[{"default":"true","handler":"http://helmsman:18007/webhooks/mist/user_new","sync":true}]},"trustedproxy":[]},"extwriters":[["s3","livepeer-catalyst-uploader -t 2592000s",["s3","s3+http","s3+https","ipfs"]]],"jwks":null,"push_settings":{"maxspeed":0,"wait":3},"streamkeys":null,"streams":{"live":{"debug":4,"name":"live","processes":[{"bitrate":120000,"codec":"opus","exit_unmask":false,"inconsequential":false,"process":"AV","restart_type":"fixed","track_inhibit":"audio=opus","track_select":"video=none","x-LSP-name":"Audio to Opus"},{"bitrate":120000000,"codec":"AAC","exit_unmask":false,"inconsequential":false,"process":"AV","restart_type":"fixed","track_inhibit":"audio=aac","track_select":"video=none","x-LSP-name":"Audio to AAC"}],"realtime":false,"source":"balance:http://foghorn:18008?fallback=push://","stop_sessions":false,"tags":[]},"live+$":{"name":"live+$","realtime":true,"source":"balance:http://foghorn:18008?fallback=push://","stop_sessions":false,"tags":["live"]},"vod":{"name":"vod","processes":[],"realtime":false,"source":"/tmp/none","stop_sessions":false,"tags":[]},"vod+$":{"name":"vod+$","realtime":false,"source":"balance:http://foghorn:18008?fallback=push://","stop_sessions":false,"tags":["vod"]}},"ui_settings":{"HTTPSUrl":"https://localhost:9090/view/","HTTPUrl":"http://localhost:8080/","sort_autopushes":{"by":"Stream","dir":1},"sort_pushes":{"by":"Statistics","dir":1},"sortstreams":{"by":"name","dir":1}},"variables":null}

0 commit comments

Comments
 (0)