1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
|
This repository contains infrastructure-as-code ansible configurations
for various pieces of the EmacsConf infrastructure.
ansible-galaxy collection install community.general
Production: needs prod-vars.yml, see prod-vars.yml.sample
Docker: needs docker-vars.yml, see docker-vars.yml.sample
* Ansible setup
We have Python 3.7 on front/pad and Python 3.13 on res, so we need Ansible 2.14 and community.general 7.x.
#+begin_src sh
rm -rf .venv
uv venv --python 3.11
source .venv/bin/activate
uv pip install "ansible-core>=2.14.0,<2.15.0"
ansible-galaxy collection install "community.general:<8.0.0" --force
ansible-galaxy collection install community.mysql --force
ansible front,res -i inventory.yml -m ping
#+end_src
* How to use this playbook
:PROPERTIES:
:CUSTOM_ID: how-to-use-this-playbook
:END:
1. Install ansible on your local machine and check out this repo.
2. Copy the ansible_vars block from conf.org to prod-vars.yml in this repo (alongside inventory.yml), or set emacsconf-ansible-directory in Emacs and then use emacsconf-ansible-tangle-vars to tangle the file.
3. scp orga@res.emacsconf.org:~/authorized_keys . (if you're setting up any user accounts)
4. Find the ansible-playbook command you want to run and try it out.
Debugging: add -v or -vv to the =ansible-playbook= command.
Due to the older version of SSH installed on front0, you will need to add =LogLevel QUIET= to your =~/.ssh/config=.
* Setting up a vault
:PROPERTIES:
:CUSTOM_ID: vault
:END:
You can store passwords in vault files if you like. [[https://stackoverflow.com/questions/37297249/how-to-store-ansible-become-pass-in-a-vault-and-how-to-use-it][More info]]
Put this text into =host_vars/media/plain= and =host_vars/upload/plain=:
#+begin_example
ansible_become_pass: "{{ vaulted_become_pass }}"
#+end_example
Use =ansible-vault create host_vars/media/crypted= and =ansible-vault create host_vars/upload/crypted= to create files with the contents:
#+begin_example
vaulted_become_pass: "yourpasswordhere"
#+end_example
To set the password for this console session:
#+begin_src sh :eval no
export VAULT_PASSWORD=...
#+end_src
To change the password for a file:
#+begin_src sh :eval no
ansible-vault rekey $FILE --ask-vault-pass
#+end_src
* Processes
:PROPERTIES:
:CUSTOM_ID: processes
:END:
At the start of the conference preparation period, change
=emacsconf-year= in [[file:group_vars/all.yml]]
To start a local copy of the wiki for testing, see [[#wiki-docker][Ikiwiki - Docker]].
* Wiki
:PROPERTIES:
:CUSTOM_ID: wiki
:END:
** Ikiwiki
:PROPERTIES:
:CUSTOM_ID: wiki-ikiwiki
:END:
*** Prod
:PROPERTIES:
:CUSTOM_ID: wiki-ikiwiki-prod
:END:
When you update htmlscrubber.pm in wiki/templates or emacsconf.setup:
ansible-playbook -i inventory.yml prod-playbook.yml --tags wiki-plugins
ansible-playbook -i docker-inventory.yml docker-reuse-playbook.yml --tags wiki-plugins
ansible-playbook -i inventory.yml prod-playbook.yml --tags wiki
*** Docker
:PROPERTIES:
:CUSTOM_ID: wiki-docker
:END:
Goal:
- [X] Load the wiki at http://localhost:28080
- [X] Add SSH key
- [X] Add as remote
- [X] Push to the wiki
- [X] Have the changes show up automatically
- [X] Have ansible copy the SSH key
file:/docker:emacsconf-front:/home/ikiwiki/emacsconf.setup
Creating:
ansible-playbook -i docker-inventory.yml docker-playbook.yml --tags wiki
Reusing:
ansible-playbook -i docker-inventory.yml docker-reuse-playbook.yml --tags wiki
Restarting after a reboot:
docker restart emacsconf-front
Copying your SSH key:
set the docker_ssh_key Ansible variable to the path of your public key
or
docker cp ~/.ssh/id_rsa.pub emacsconf-front:/home/ikiwiki/.ssh/authorized_keys2
docker exec emacsconf-front chown ikiwiki:ikiwiki /home/ikiwiki/.ssh/authorized_keys2
docker exec emacsconf-front chmod 600 /home/ikiwiki/.ssh/authorized_keys2
http://localhost:28080/
ssh localhost -p 2222
docker exec -it emacsconf-front /bin/bash
git remote add docker ssh://ikiwiki@127.0.0.1:2222/var/www/wiki.git
Debugging
ssh wiki 'cd /var/www/wiki.git; git update-ref refs/heads/master HEAD^' && git push docker 2022-pages
Stuck wiki:
ssh ikiwiki@localhost -p 2222 ikiwiki --setup /home/ikiwiki/emacsconf.setup -v
* Processing prerecs
:PROPERTIES:
:CUSTOM_ID: processing-prerecs
:END:
1. Update =group_vars/all.yml=: set =emacsconf_year=.
2. In the conf.org file, call =M-x emacsconf-set-file-prefixes= to set the file prefixes. Tweak as needed.
3. Export the talks.json with =M-x emacsconf-ansible-export-talks=.
4. ansible-playbook -i inventory.yml prod-playbook.yml --tags prerec
5. ansible-playbook -i inventory.yml prod-playbook.yml --tags caption
6. ansible-playbook -i inventory.yml local-playbook.yml
When you receive a file, create a directory for it named =~/current/files/$slug=. Copy the uploaded file as =$video_slug--original.$extension=, or use =rename-original.sh $slug $file=.
Then call =process-prerec.sh $file=. It will launch some screen sessions for reencoding the file and creating the VTT.
* Setting up the backstage area
:PROPERTIES:
:CUSTOM_ID: setting-up-the-backstage-area
:END:
1. Doublecheck the media host in [[file:inventory.yml]] and the variables in [[file:roles/media/defaults/main.yml]].
2. ansible-playbook -i inventory.yml prod-playbook.yml --tags media --ask-become-pass
(or =ansible-playbook -i inventory.yml prod-playbook.yml --tags media --ask-vault-pass= if you've [[#vault][stored it in a vault]])
3. Update the following variables in your Emacs configuration:
- emacsconf-backstage-dir
- emacsconf-backstage-phase
4. [[elisp:(let ((dir (format "~/proj/emacsconf/%s/cache" emacsconf-year))) (unless (file-directory-p dir) (make-directory dir)))][(Run)]] Create ~/proj/emacsconf/{year}/cache on your local system.
5. Copy over the include-in-index-footer.html and include-in-public-index.html templates from other years. (Backup: [[file:roles/media/templates/]]
6. elisp:emacsconf-publish-talks-json-to-files
7. [[elisp:emacsconf-publish-backstage-index]]
* Upload service
:PROPERTIES:
:CUSTOM_ID: upload-service
:END:
1. [ ] Check [[file:group_vars/all.yml]] to make sure emacsconf_year is set.
2. [ ] =ansible-playbook -i inventory.yml prod-playbook.yml --tags upload --ask-become-pass= (or =ansible-playbook -i inventory.yml prod-playbook.yml --tags upload --ask-vault-pass= if you've [[#vault][stored it in a vault]], or =ansible-playbook -i inventory.yml prod-playbook.yml --tags upload= if the vault password is already in the environment variable =VAULT_PASSWORD=.)
3. [ ] Upload a test file through https://upload.emacsconf.org/. The password is defined in the upload_password Ansible variable.
4. [ ] Check that [[file:~/proj/emacsconf/emacsconf-ansible/README.org::#setting-up-the-backstage-area][the backstage area has been set up]]. Note that files are not automatically copied to the backstage area.
5. [ ] Send speakers the e-mail about the upload service
- elisp:emacsconf-mail-upload-and-backstage-info-to-waiting-for-prerecs
- elisp:emacsconf-mail-upload-and-backstage-info if mailing individually
Other notes:
- /ssh:media|sudo:upload@media:~upload
- /ssh:media|sudo::/etc/nginx/sites-available
- sudo service upload start
* Publishing
:PROPERTIES:
:CUSTOM_ID: publishing
:END:
Goals:
- [X] Set up Emacs 28.2 or a newer one
- [X] Check out the repositories
- [X] Load the configuration
- [X] Publish the backstage index
- [X] Publish the watchpages
- [X] Publish schedule to the wiki and push
- [ ] Have nice interactive setup
- [ ] Publish backstage index on a hook
- [ ] Connect to IRC and announce talks
- [ ] Push talk info the text files on the stream
- [ ] Start mpv in the right display
- [ ] Publish the prerec files
- [ ] Publish the prerec on the page
** Prod
:PROPERTIES:
:CUSTOM_ID: publishing-prod
:END:
To run the playbook and publish the main schedule:
#+begin_src sh
ansible-playbook -i inventory.yml prod-playbook.yml --tags wiki-publish --extra-vars='{"force_publish": true}'
#+end_src
#+RESULTS:
:results:
:end:
Update a specific talk's before/nav and the main schedule: (ex: wayland)
ansible-playbook playbook.yml -e '{"slug": "wayland"}' -i inventory.yml --tags publish
Force-publish the schedule:
ansible-playbook -i inventory.yml prod-playbook.yml --tags publish -e force_publish=true
** Development
:PROPERTIES:
:CUSTOM_ID: publishing-development
:END:
** Docker
:PROPERTIES:
:CUSTOM_ID: publishing-docker
:END:
Creating:
ansible-playbook -i docker-inventory.yml docker-playbook.yml --tags wiki,publish
Reusing:
ansible-playbook -i docker-inventory.yml docker-reuse-playbook.yml --tags publish
With docker:
https://stackoverflow.com/questions/24738264/how-to-test-ansible-playbook-using-docker
* Pad
:PROPERTIES:
:CUSTOM_ID: pad
:END:
Before generating pads, use elisp:emacsconf-publish-talks-json-to-files to create the talks.json used.
** Production
:PROPERTIES:
:CUSTOM_ID: pad-production
:END:
ansible-playbook -i inventory.yml prod-playbook.yml --tags pad,proxy
To fall back to wikimedia rewrite:
ansible-playbook -i inventory.yml prod-playbook.yml --tags proxy --extra-vars='{"use_wikimedia": true}'
You can still access pads directly with direct/p like this:
https://pad.emacsconf.org/direct/p/2022-journalism
To undo wikimedia rewrite:
ansible-playbook -i inventory.yml prod-playbook.yml --tags proxy
To prepare for a load test:
ansible-playbook -i inventory.yml prod-playbook.yml --tags pad --extra-vars='{"etherpad_load_test": true}'
To create pads:
ansible-playbook -i inventory.yml prod-playbook.yml --tags create-pads
** Docker
:PROPERTIES:
:CUSTOM_ID: pad-docker
:END:
Creating:
ansible-playbook -i docker-inventory.yml docker-playbook.yml --tags pad
Reusing an existing container:
ansible-playbook -i docker-inventory.yml docker-reuse-playbook.yml --tags pad
Connecting:
docker exec -it emacsconf-pad /bin/bash
Creating pads
ansible-playbook -i docker-inventory.yml docker-reuse-playbook.yml --tags create-pads
file:/docker:emacsconf-pad:/home/etherpad/etherpad/
Getting the API key
#+NAME: pad-key
#+begin_src sh
docker exec emacsconf-pad cat /home/etherpad/etherpad/APIKEY.txt
#+end_src
#+RESULTS: pad-key
:results:
b7a15dc34cc7f6917cca6cd9a2b4b92145af7c7cd9b341af34869ab8cd3568be
:end:
#+begin_src sh :var padkey=pad-key
echo curl "http://localhost:9001/api/1/createPad?apikey=$padkey&padID=emacsconf-2022"
curl "http://localhost:9001/api/1/createPad?apikey=$padkey&padID=emacsconf-2022"
#+end_src
#+RESULTS:
:results:
curl http://localhost:9001/api/1/createPad?apikey=b7a15dc34cc7f6917cca6cd9a2b4b92145af7c7cd9b341af34869ab8cd3568be&padID=emacsconf-2022
{"code":0,"message":"ok","data":null}
:end:
** Useful
:PROPERTIES:
:CUSTOM_ID: pad-useful
:END:
https://github.com/systemli/ansible-role-etherpad
https://gist.github.com/aaronpk/7307172
* Pad proxy
:PROPERTIES:
:CUSTOM_ID: pad-proxy
:END:
ansible-playbook -i inventory.yml prod-playbook.yml --tags proxy --extra-vars='{"use_wikimedia": false}'
ansible-playbook -i inventory.yml prod-playbook.yml --tags proxy --extra-vars='{"use_wikimedia": true}'
* Stream
:PROPERTIES:
:CUSTOM_ID: stream
:END:
** Prod
:PROPERTIES:
:CUSTOM_ID: stream-prod
:END:
Setting up icecast:
ansible-playbook -i inventory.yml prod-playbook.yml --tags stream
** Testing
:PROPERTIES:
:CUSTOM_ID: stream-testing
:END:
Runs the ffmpeg command on res
ansible-playbook -i inventory.yml prod-playbook.yml --tags test -e icecast_test_file=/home/orga/test.webm -e icecast_test=file -e icecast_test_track=dev
Play the stream with MPV:
ansible-playbook -i inventory.yml prod-playbook.yml --tags test -e icecast_test_track=dev -e icecast_test=mpv
Use a test pattern (don't know if this works)
ansible-playbook -i inventory.yml prod-playbook.yml --tags test -e icecast_test_track=dev -e icecast_test=pattern
** Creating the fallback files
:PROPERTIES:
:CUSTOM_ID: stream-creating-the-fallback-files
:END:
ffmpeg -y -f lavfi -i anullsrc=channel_layout=stereo:sample_rate=48000 -loop 1 -r 20 -t 10 -i sorry.png -c:v libvpx -c:a libvorbis -color_primaries 1 -color_trc 1 -colorspace 1 -crf 30 -g 120 -minrate 1.5M -b:v 1500 -g 120 -maxrate 1.5M -cluster_time_limit 5100 -shortest sorry.webm
ffmpeg -y -f lavfi -i anullsrc=channel_layout=stereo:sample_rate=48000 -loop 1 -r 20 -t 10 -i sorry.png -vf scale=854:480 -c:v libvpx -c:a libvorbis -color_primaries 1 -color_trc 1 -colorspace 1 -crf 30 -g 120 -minrate 1.5M -b:v 1500 -g 120 -maxrate 1.5M -cluster_time_limit 5100 -shortest sorry-480p.webm
* OBS
:PROPERTIES:
:CUSTOM_ID: obs
:END:
ansible-playbook -i inventory.yml prod-playbook.yml --tags obs
Resizing VNC after connection
xrandr -s 1280x720
** Firefox
:PROPERTIES:
:CUSTOM_ID: obs-firefox
:END:
*** Firefox profiles like to be created in an X environment
:PROPERTIES:
:CUSTOM_ID: obs-firefox-firefox-profiles-like-to-be-created-in-an-x-environment
:END:
firefox -no-remote -CreateProfile "{{ emacsconf_id }}-{{ item.item.id }}
*** Install Tampermonkey extension and scripts :manual:
:PROPERTIES:
:CUSTOM_ID: obs-firefox-install-tampermonkey-extension-and-scripts
:END:
For each track:
1. Install the Tampermonkey extension by going to https://addons.mozilla.org/en-US/firefox/addon/tampermonkey/ .
2. Install the BBB script by clicking on the Tampermonkey extension, choosing *Install New Script*, and using this as the URL. Enable checking for updates.
https://live.emacsconf.org/emacsconf-tampermonkey-bbb.js
(these are updated by the Ansible playbook tag "static")
Press =Ctrl+s= to save.
3. Add this script for IRC:
https://live.emacsconf.org/emacsconf-tampermonkey-irc.js
4. Join an BBB meeting and switch out of full-screen with F11. Check the address bar to see if autoplay is disabled (crossed-out autoplay icon). If it is, click on it and change *Block audio* to *Allow audio and video*.
** How to update scenes from the gen copy
:PROPERTIES:
:CUSTOM_ID: obs-how-to-update-scenes-from-the-gen-copy
:END:
ssh emacsconf-gen@res.emacsconf.org -p 46668 "cat ~/.config/obs-studio/basic/scenes/emacsconf.json" | jq 'walk(if type == "string" then gsub("emacsconf"; "{{ emacsconf_id }}") else . end)' > roles/obs/templates/scenes.json
ansible-playbook -i inventory.yml prod-playbook.yml --tags obs-scene
* Media
:PROPERTIES:
:CUSTOM_ID: media
:END:
ansible-playbook -i inventory.yml prod-playbook.yml --tags media
* Captioning
:PROPERTIES:
:CUSTOM_ID: captioning
:END:
Set up whisper:
ansible-playbook -i inventory.yml prod-playbook.yml --tags caption
Update caption script:
ansible-playbook -i inventory.yml prod-playbook.yml --tags process-captions
ffmpeg -y -i handwritten/reencode.webm -t 60 -vcodec copy -acodec copy test.webm
* Other useful things
:PROPERTIES:
:CUSTOM_ID: other-useful-things
:END:
nodemon -w . -e yml -x 'ansible-playbook -i inventory.yml prod-playbook.yml --tags vnc; true'
* Restreaming
:PROPERTIES:
:ID: 20251122T182719.845166
:CUSTOM_ID: restreaming
:END:
Add something like this to your ~prod-vars.yml~:
#+begin_src emacs-lisp
restreaming_platforms:
- name: youtube
streams:
- name: gen
key: xxxx-xxxx-xxxx-xxxx-xxxx
url: https://www.youtube.com/watch?v=xxxxxxxxxxx
studio: https://studio.youtube.com/video/xxxxxxxxxxx/livestreaming
source: gen.webm
- name: dev
key: xxxx-xxxx-xxxx-xxxx-xxxx
url: https://www.youtube.com/watch?v=xxxxx-xxxxx
studio: https://studio.youtube.com/video/xxxxx-xxxxx/livestreaming
source: dev.webm
- name: test
key: xxxx-xxxx-xxxx-xxxx-xxxx
studio: https://studio.youtube.com/video/xxxxxxxxxxx/livestreaming
url: https://youtu.be/xxxxxxxxxxx
source: gen.webm
stream_url: rtmp://a.rtmp.youtube.com/live2
backup_stream: rtmp://b.rtmp.youtube.com/live2?backup=1
- name: toobnix
stream_url: rtmp://toobnix.org:1935/live
streams:
- name: gen
key: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
url: https://toobnix.org/w/xxxxxxxxxxxxxxxxxxxxxx
source: gen.webm
- name: dev
key: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
url: https://toobnix.org/w/xxxxxxxxxxxxxxxxxxxxxx
source: dev.webm
- name: test
key: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
url: https://toobnix.org/w/xxxxxxxxxxxxxxxxxxxxxx
source: gen.webm
#+end_src
This will set up scripts on the live0 server.
It doesn't get automatically started, so you'll also need to call ~screen -S restream-$SHIFT_ID-youtube~ and ~screen -S restream-$TRACK_ID-toobnix~.
* BBB
:PROPERTIES:
:CUSTOM_ID: bbb
:END:
ansible-playbook -i inventory.yml prod-playbook.yml --tags bbb
* Local testing with vagrant
:PROPERTIES:
:CUSTOM_ID: local-testing-with-vagrant
:END:
Rough notes on local testing
#+begin_src ruby :tangle test/front/Vagrantfile
# -*- mode: ruby -*-
Vagrant.configure("2") do |config|
config.vm.box = "debian/bookworm64"
config.vm.define "pad" do |pad|
end
config.vm.provider "virtualbox" do |vb|
vb.memory = "2048"
end
config.vm.network "private_network", ip: "192.168.56.2"
config.vm.provision "ansible" do |ansible|
ansible.playbook = "../../vagrant-playbook.yml"
end
end
#+end_src
In ~test/front~: ~vagrant up --provision~
ansible-galaxy role install systemli.etherpad
nodemon -e '*' -w ../../roles/pad/ -x "vagrant destroy -f && vagrant up --provision"
Backing up:
ansible-playbook -i inventory.yml backup-playbook.yml
|