1
0
Fork 0

Major work complete

- Added some documentation for setup process
- Added productivity tools to configuration
- Refactored artwork location
- Improved Ansible privilege escalation
- Default to 720p profile
master
Ambrose Chua 2020-02-16 00:28:36 +08:00
parent b054a9a67a
commit d1831d7044
24 changed files with 329 additions and 35 deletions

View File

@ -1,2 +1,101 @@
# fossasia-video
The FOSSASIA video recording setup
## Overview
## Installing Debian
For the recording machines, get a fresh copy of Debian, and install it with the following settings:
- Username: opentech
- Hostname: model-increment
- Example: x220-01
- Add GNOME Desktop
- Add OpenSSH Server
If a GNOME Desktop and SSH daemon is already installed, a reinstall is not required but recommended.
## WireGuard
To set up the overlay WireGuard network to manage machines everywhere, a server needs to be set up. [`wireguard-negotiator`](https://github.com/serverwentdown/wireguard-negotiator) is a tool written to automate some of the key exchange, that must be run on a publicly accessible server as root:
```
# Create WireGuard interface
ip link add dev wg1 type wireguard
ip addr add fd11:f055:a514:0000::1/64 dev wg1
# Configure the interface once. Assumes the configuration file exists
# See WireGuard docs on how to write this configuraion file
wg setconf wg1 /etc/wireguard/wg1.conf
# Bring up the interface
ip link set wg1 up
wireguard-negotiator server -i wg1 -e [hostname] -l :8080 -I -B
```
On every recording machine, the client can be easily configured like so:
```
# For now, we have to manually install WireGuard
echo "deb http://deb.debian.org/debian/ unstable main" | sudo tee /etc/apt/sources.list.d/unstable.list
printf 'Package: *\nPin: release a=unstable\nPin-Priority: 90\n' | sudo tee /etc/apt/preferences.d/limit-unstable
sudo apt update
sudo apt install wireguard
# TODO: validate this section
sudo systemctl enable --now systemd-networkd
wget -O wgn http://[hostname]:8080
chmod +x wgn
sudo ./wgn request -s http://[hostname]:8080
```
## Configuring Rooms
To specify the room for a specific host, do the following:
```
echo the_room_id > ~opentech/room_id
echo teh_room_type > ~opentech/room_type
```
This step is optional. This and the following steps should be done for every change in room or setup of the laptop.
## Exporting Hosts
Export all hosts on the overlay network from WireGuard configuration:
```
wireguard-negotiator dump > wireguard.list
```
This list of IPs can be exported into our Ansible hosts format as such:
```
go run event-generate.go opentech < wireguard.list > event
```
The script `event-fetch-generate.sh` does the exporting and generating of the `event` inventory.
## Running Playbooks
Before running any Playbooks, switch to SSH authentication:
```
ansible-playbook -Kf 8 -kc paramiko -i event ssh-key.yml
ansible -Kf 8 -kc paramiko -b -i event all -a reboot
```
Now, plays can be run like so:
```
./play [inventory] [playbook]
# Which executes the following command
ansible-playbook -Kf 4 -i [inventory] [playbook]
# Example:
./play event recorders.yml
```
## Install Wireless Drivers
```
ansible -Kf 8 -b -i event all -a 'apt install firmware-iwlwifi'
```

View File

@ -1,6 +1,3 @@
[recorders:children]
testgroup
[testgroup]
#user@10.10.2.5 room_id=test
ambrose@10.10.0.90 room_id=test
[recorders]
x220-01 ansible_host=fd11:f055:a514::2 ansible_user=opentech room_id= room_type=
x230-01 ansible_host=fd11:f055:a514::3 ansible_user=opentech room_id=testroom1 room_type=special

View File

@ -0,0 +1,7 @@
#!/bin/sh
set -e
echo "Fetching event inventory"
ssh saguaro /usr/local/bin/wireguard-negotiator dump -i wg1 | go run event-generate.go opentech > event

59
ansible/event-generate.go Normal file
View File

@ -0,0 +1,59 @@
package main
import (
"bufio"
"bytes"
"fmt"
"os"
"os/exec"
"strings"
)
func main() {
s := bufio.NewScanner(os.Stdin)
if len(os.Args) != 1+1 {
fmt.Fprintf(os.Stderr, "not enough arguments\nusage: %s [ssh user]\n", os.Args[0])
return
}
user := os.Args[1]
fmt.Printf("[recorders]\n")
for s.Scan() {
host := s.Text()
if strings.HasPrefix(host, "#") {
// Is a comment
continue
}
if strings.HasSuffix(host, ":0") {
// Is a "system" host
continue
}
hostname, roomId, roomType, err := discover(host, user)
if err != nil {
fmt.Fprintf(os.Stderr, "host %s discovery failed: %v\n", host, err)
}
fmt.Printf("%s ansible_host=%s ansible_user=%s room_id=%s room_type=%s\n", hostname, host, user, roomId, roomType)
}
}
func discover(host, user string) (hostname, roomId, roomType string, err error) {
cmd := exec.Command("/usr/bin/ssh", "-l", user, host, "sh", "-c", "hostname; cat room_id; cat room_type; exit 0")
fmt.Fprintf(os.Stderr, "command: %s\n", cmd)
var out bytes.Buffer
cmd.Stdout = &out
err = cmd.Run()
if err != nil {
return
}
hostname, err = out.ReadString('\n')
if err != nil {
return
}
hostname = strings.TrimSpace(hostname)
roomId, _ = out.ReadString('\n')
roomId = strings.TrimSpace(roomId)
roomType, _ = out.ReadString('\n')
roomType = strings.TrimSpace(roomType)
return
}

View File

@ -3,6 +3,11 @@
room_id: unknown
# Overwrite in inventory if cannot cope
record_profile: 1080p
record_profile: 720p
# Overwrite in inventory if want to use more storage to use less CPU
record_fast: false
record_user: mixer
record_home: /home/mixer
autostart: true

View File

@ -1,3 +1,5 @@
#!/bin/sh
ansible-playbook -Kbf 1 -i "$1" "$2"
set -e
ansible-playbook -Kf 4 -i "$1" "$2"

4
ansible/productivity.yml Normal file
View File

@ -0,0 +1,4 @@
---
- hosts: recorders
roles:
- productivity

View File

@ -0,0 +1,7 @@
---
- hosts: recorders
roles:
- role: recorder
- role: monitoring-client
vars:
autostart: false

View File

@ -0,0 +1,30 @@
---
# Credits: Michael Heap
- name: Does the Google apt file exist?
become: yes
command: test -f {{ apt_file }}
register: google_apt_exists
ignore_errors: True
- name: Add Google Chrome key
become: yes
shell: wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -
when: google_apt_exists.rc == 1
- name: Add Google Chrome repo
become: yes
copy: content="deb http://dl.google.com/linux/chrome/deb/ stable main" dest={{ apt_file }} owner=root group=root mode=644
when: google_apt_exists.rc == 1
- name: Update apt cache
become: yes
apt: update_cache=yes
when: google_apt_exists.rc == 1
- name: Install Google Chrome
become: yes
apt:
state: latest
pkg: google-chrome-stable

View File

@ -0,0 +1,8 @@
---
- include: chrome.yml
vars:
- apt_file: /etc/apt/sources.list.d/google-chrome.list
- include: vscode.yml
vars:
- apt_file: /etc/apt/sources.list.d/vscode.list
- include: packages.yml

View File

@ -0,0 +1,10 @@
---
- name: install editors
become: yes
apt:
state: latest
name:
- neovim
- emacs

View File

@ -0,0 +1,30 @@
---
# Credits: Michael Heap
- name: Does the vscode apt file exist?
become: yes
command: test -f {{ apt_file }}
register: vscode_apt_exists
ignore_errors: True
- name: Add Microsoft key
become: yes
shell: wget -q -O - https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
when: vscode_apt_exists.rc == 1
- name: Add vscode repo
become: yes
copy: content="deb https://packages.microsoft.com/repos/vscode stable main" dest={{ apt_file }} owner=root group=root mode=644
when: vscode_apt_exists.rc == 1
- name: Update apt cache
become: yes
apt: update_cache=yes
when: vscode_apt_exists.rc == 1
- name: Install vscode
become: yes
apt:
state: latest
pkg: code

View File

@ -2,19 +2,17 @@
- name: create artwork directory
file:
dest: "/opt/artwork/{{ event.id }}"
dest: "{{ mixer_user.home }}/artwork/{{ event.id }}"
state: directory
recurse: yes
owner: root
group: root
mode: u=rwx,g=rx,o=rx
become: yes
become_user: mixer
- name: copy backgrounds
copy:
src: "../../../artwork/{{ event.id }}/{{ item }}.png"
dest: "/opt/artwork/{{ event.id }}"
owner: root
group: root
dest: "{{ mixer_user.home }}/artwork/{{ event.id }}"
mode: u=rw,g=r,o=r
with_items:
- side-by-side
@ -22,3 +20,5 @@
- side-by-side-43
- side-by-side-43-reverse
- blank
become: yes
become_user: mixer

View File

@ -1,10 +1,12 @@
---
- name: generate hosts file
become: yes
template:
src: etc-hosts.j2
dest: /etc/hosts
- name: set hostname to room_id
become: yes
hostname:
name: "room-{{ room_id }}"

View File

@ -1,6 +1,6 @@
---
- include: user.yml
- include: hostname.yml
#- include: hostname.yml
- include: packages.yml
- include: artwork.yml
- include: obs.yml

View File

@ -5,39 +5,39 @@
dest: "{{ mixer_user.home }}/.config/obs-studio/{{ item }}"
state: directory
recurse: yes
owner: mixer
group: mixer
mode: u=rwx,g=rx,o=rx
with_items:
- basic/profiles/1080p
- basic/profiles/720p
- basic/scenes
become: yes
become_user: mixer
- name: create videos directory
file:
dest: "{{ mixer_user.home }}/Videos/{{ event.id }}/{{ room_id }}"
state: directory
recurse: yes
owner: mixer
group: mixer
mode: u=rwx,g=rx,o=rx
become: yes
become_user: mixer
- name: generate base obs configuration files
template:
src: "obs-studio/{{ item }}.j2"
dest: "{{ mixer_user.home }}/.config/obs-studio/{{ item }}"
owner: mixer
group: mixer
mode: u=rw,g=r,o=r
with_items:
- global.ini
- basic/profiles/1080p/basic.ini
- basic/profiles/720p/basic.ini
become: yes
become_user: mixer
- name: generate event obs configuration files
template:
src: "obs-studio/basic/scenes/event_id.json.j2"
dest: "{{ mixer_user.home }}/.config/obs-studio/basic/scenes/{{ event.id }}.json"
owner: mixer
group: mixer
mode: u=rw,g=r,o=r
become: yes
become_user: mixer

View File

@ -1,12 +1,14 @@
---
- name: install general packages
become: yes
apt:
state: latest
name:
- git
- name: install packages required to be a recorder
become: yes
apt:
state: latest
name:

View File

@ -1,10 +1,12 @@
---
- name: create mixer group
become: yes
group:
name: mixer
- name: create mixer user with password mixer
become: yes
user:
name: mixer
group: mixer
@ -14,7 +16,8 @@
register: mixer_user
- name: enable gdm autologin to mixer user
copy:
become: yes
template:
src: gdm.conf
dest: /etc/gdm3/daemon.conf
owner: root

View File

@ -8,9 +8,11 @@
# Uncomment the line below to force the login screen to use Xorg
#WaylandEnable=false
{% if autostart %}
# Enabling automatic login
AutomaticLoginEnable = true
AutomaticLogin = mixer
{% endif %}
# Enabling timed login
# TimedLoginEnable = true

View File

@ -11,7 +11,7 @@ OutputCY=1080
Mode=Simple
[Audio]
SampleRate=48000
SampleRate=44100
[Hotkeys]
OBSBasic.StartRecording={\n "bindings": [\n {\n "control": true,\n "key": "OBS_KEY_RETURN"\n }\n ]\n}
@ -20,7 +20,8 @@ OBSBasic.Transition={\n "bindings": [\n {\n "key": "OBS_KEY
[SimpleOutput]
RecFormat=mkv
RecQuality=Small
RecQuality=Stream
VBitrate=3000
{% if record_fast %}
RecEncoder=x264_lowcpu
{% else %}

View File

@ -11,7 +11,7 @@ OutputCY=720
Mode=Simple
[Audio]
SampleRate=48000
SampleRate=44100
[Hotkeys]
OBSBasic.StartRecording={\n "bindings": [\n {\n "control": true,\n "key": "OBS_KEY_RETURN"\n }\n ]\n}
@ -20,7 +20,8 @@ OBSBasic.Transition={\n "bindings": [\n {\n "key": "OBS_KEY
[SimpleOutput]
RecFormat=mkv
RecQuality=Small
RecQuality=Stream
VBitrate=3000
{% if record_fast %}
RecEncoder=x264_lowcpu
{% else %}

View File

@ -159,7 +159,7 @@
"push-to-talk": false,
"push-to-talk-delay": 0,
"settings": {
"file": "/opt/artwork/{{ event.id }}/blank.png",
"file": "{{ mixer_user.home }}/artwork/{{ event.id }}/blank.png",
"unload": true
},
"sync": 0,
@ -446,7 +446,7 @@
"push-to-talk": false,
"push-to-talk-delay": 0,
"settings": {
"file": "/opt/artwork/{{ event.id }}/side-by-side-43-reverse.png",
"file": "{{ mixer_user.home }}/artwork/{{ event.id }}/side-by-side-43-reverse.png",
"unload": true
},
"sync": 0,
@ -609,7 +609,7 @@
"push-to-talk": false,
"push-to-talk-delay": 0,
"settings": {
"file": "/opt/artwork/{{ event.id }}/side-by-side-43.png",
"file": "{{ mixer_user.home }}/artwork/{{ event.id }}/side-by-side-43.png",
"unload": true
},
"sync": 0,
@ -913,7 +913,7 @@
"push-to-talk": false,
"push-to-talk-delay": 0,
"settings": {
"file": "/opt/artwork/{{ event.id }}/side-by-side.png",
"file": "{{ mixer_user.home }}/artwork/{{ event.id }}/side-by-side.png",
"unload": false
},
"sync": 0,
@ -1103,7 +1103,7 @@
"push-to-talk": false,
"push-to-talk-delay": 0,
"settings": {
"file": "/opt/artwork/{{ event.id }}/side-by-side-reverse.png",
"file": "{{ mixer_user.home }}/artwork/{{ event.id }}/side-by-side-reverse.png",
"unload": false
},
"sync": 0,

View File

@ -9,8 +9,8 @@ cx=720
cy=580
[BasicWindow]
geometry=AdnQywACAAAAAABDAAAAGwAAA/8AAAL/AAAAWAAAAEYAAAOuAAACwgAAAAACAAAABAA=
DockState=AAAA/wAAAAD9AAAAAQAAAAMAAAO9AAAA+/wBAAAABfsAAAAUAHMAYwBlAG4AZQBzAEQAbwBjAGsBAAAAAAAAANsAAACoAP////sAAAAWAHMAbwB1AHIAYwBlAHMARABvAGMAawEAAADhAAAA3AAAAKgA////+wAAABIAbQBpAHgAZQByAEQAbwBjAGsBAAABwwAAASoAAADkAP////sAAAAeAHQAcgBhAG4AcwBpAHQAaQBvAG4AcwBEAG8AYwBrAAAAAlgAAAC/AAAAggD////7AAAAGABjAG8AbgB0AHIAbwBsAHMARABvAGMAawEAAALzAAAAygAAAJsA////AAADvQAAAZkAAAAEAAAABAAAAAgAAAAI/AAAAAA=
geometry=AdnQywACAAAAAAAAAAAAGwAABVUAAAL/AAAAAAAAAEAAAAQ2AAAC/wAAAAACAAAABVY=
DockState=AAAA/wAAAAD9AAAAAQAAAAMAAAVWAAABF/wBAAAABfsAAAAUAHMAYwBlAG4AZQBzAEQAbwBjAGsBAAAAAAAAAToAAACoAP////sAAAAWAHMAbwB1AHIAYwBlAHMARABvAGMAawEAAAFAAAABPAAAAKgA////+wAAABIAbQBpAHgAZQByAEQAbwBjAGsBAAACggAAAawAAADkAP////sAAAAeAHQAcgBhAG4AcwBpAHQAaQBvAG4AcwBEAG8AYwBrAAAAAlgAAAC/AAAAggD////7AAAAGABjAG8AbgB0AHIAbwBsAHMARABvAGMAawEAAAQ0AAABIgAAAJoA////AAAFVgAAAXIAAAAEAAAABAAAAAgAAAAI/AAAAAA=
PreviewEnabled=true
AlwaysOnTop=false
SceneDuplicationMode=true

25
ansible/ssh-key.yml Normal file
View File

@ -0,0 +1,25 @@
---
- hosts: recorders
tasks:
- name: set permissions for .ssh directory
file:
path: "{{ ansible_env.HOME }}/.ssh"
state: directory
mode: u=rwx,g=-rwx,o=-rwx
- name: create authorized_keys file
file:
path: "{{ ansible_env.HOME }}/.ssh/authorized_keys"
state: touch
mode: u=rwx,g=r-wx,o=r-wx
- name: insert ambrose's public ssh key
blockinfile:
dest: "{{ ansible_env.HOME }}/.ssh/authorized_keys"
block: |
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDDBsAEpJLRUzF9O58EkRFAe+WFp46SNEEz6ChOEkzWs+Vn4b60uKABXB60l56S1Ok6PHlNxyIlLuF+IXUOfalO+V9HXxZmjdHp7SibOXcEDFRDnCgGqnRTwd5zEbdMnZ9g0ia7NnIeaS7M5pXGtir7S86pNNaVWWnBvobDuc1As4NGIHa7hPHPOsPRgjNgB6YqaRq6a98j1yGghMiQJJvsBeZ0S00MZp9lfUiB+jrxhDgGyPsU5M9U+ObJmOFlaLx5XqZW3/5tTJoEmyD/vRV6IzOhhR6PPgGpQXJBdmrbJOKWtTwckwWE2xR+rs3J154OyZadkJ9+1aj/EKleTYs5GfDzGQeTb/wsyRz3tgTesFcXW/klVYVEcvZZxPvOoMPUK8vtYIt2LiFJov+/EQu5wfeilLURfZwKk2fBIC+CFUwg6ewogb4Ynvxv7++J11+7uMSOkuqu/0t/7rrv4TDt06dtA5oUNfZ5cUH0/H/KX48DkCp+mRI7S5uJ6majXZEm5Nmi7u+gOCSjAewe6Ex++I91MsX3WrgVG5OUffx/QTsLeRhT9ZMAlnED7lcTXNhDCEmJif87CQFucRnrkO9FvDnZG2i9721MLGo9Sf/M7AliwMH7fcVucgvY4AJuESspEjWjQn9YEqhp1cDb/PtNZtRl/v1TJOV4eQUDSWusdw== ambrose-yubikey
- name: prevent password login
become: yes
blockinfile:
dest: /etc/ssh/sshd_config
block: |
PasswordAuthentication no