Compare commits
2 commits
ddc990b522
...
47c2c003d1
Author | SHA1 | Date | |
---|---|---|---|
47c2c003d1 | |||
515545cd24 |
10 changed files with 368 additions and 5 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -1,8 +1,3 @@
|
||||||
# sorry but I don't need my network config public
|
|
||||||
setup/network.toml
|
|
||||||
# also other config contains like access tokens so just hide everything
|
|
||||||
setup/
|
|
||||||
|
|
||||||
# rust/cargo
|
# rust/cargo
|
||||||
/target/
|
/target/
|
||||||
|
|
||||||
|
|
4
setup/autostart.toml
Normal file
4
setup/autostart.toml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
# setup an autostarting kiosk that runs a webpage in a browser
|
||||||
|
[kiosk]
|
||||||
|
page = "https://time.is"
|
||||||
|
user = "kiosk"
|
8
setup/network.toml
Normal file
8
setup/network.toml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# enable connecting the raspberry pi into your tailscale network
|
||||||
|
tailscale = true
|
||||||
|
|
||||||
|
# add a wifi network
|
||||||
|
[[wifi]]
|
||||||
|
ssid = "eduroam"
|
||||||
|
security = "WPA-PSK"
|
||||||
|
password = "yoursupersecretpassword"
|
33
setup/os.toml
Normal file
33
setup/os.toml
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
[alpine]
|
||||||
|
# the alpine version. I recommend always using the latest available
|
||||||
|
branch = "v3.17"
|
||||||
|
|
||||||
|
# aarch64 is required if you want to run some software like a browser
|
||||||
|
arch = "aarch64"
|
||||||
|
|
||||||
|
# unless you have a local mirror that you know will be fast, just leave this empty
|
||||||
|
mirror = "https://ftp.halifax.rwth-aachen.de/alpine"
|
||||||
|
|
||||||
|
# here you can add some extra repositories and their signing keys
|
||||||
|
extra_repos = []
|
||||||
|
extra_keys = []
|
||||||
|
|
||||||
|
[host]
|
||||||
|
# set your local keyboard layout
|
||||||
|
keymap = "de"
|
||||||
|
keymap_variant = "de-dvorak"
|
||||||
|
|
||||||
|
# create a user for you to log in
|
||||||
|
[[user]]
|
||||||
|
name = "msrd0"
|
||||||
|
password = "changeme"
|
||||||
|
sudo = true
|
||||||
|
authorized_keys = [
|
||||||
|
# add your ssh key(s) here
|
||||||
|
]
|
||||||
|
|
||||||
|
# create a user for the autostarting kiosk
|
||||||
|
[[user]]
|
||||||
|
name = "kiosk"
|
||||||
|
password = "changeme"
|
||||||
|
groups = ["audio", "cdrom", "dialout", "floppy", "input", "uucp", "video"]
|
7
setup/packages.toml
Normal file
7
setup/packages.toml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# install some extra alpine packages
|
||||||
|
install = [
|
||||||
|
"emacs-nox", "tmux",
|
||||||
|
]
|
||||||
|
|
||||||
|
# add openrc units to autostart
|
||||||
|
autostart = []
|
14
src/setup/autostart.rs
Normal file
14
src/setup/autostart.rs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct Autostart {
|
||||||
|
pub kiosk: Kiosk
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct Kiosk {
|
||||||
|
pub page: String,
|
||||||
|
pub user: String
|
||||||
|
}
|
45
src/setup/mod.rs
Normal file
45
src/setup/mod.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
//! This module contains definitions to read the setup files.
|
||||||
|
use anyhow::Context as _;
|
||||||
|
use serde::de::DeserializeOwned;
|
||||||
|
use std::{
|
||||||
|
fs,
|
||||||
|
path::{Path, PathBuf}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub mod autostart;
|
||||||
|
pub mod network;
|
||||||
|
pub mod os;
|
||||||
|
pub mod packages;
|
||||||
|
|
||||||
|
use autostart::Autostart;
|
||||||
|
use network::Network;
|
||||||
|
use os::Os;
|
||||||
|
use packages::Packages;
|
||||||
|
|
||||||
|
pub struct Setup {
|
||||||
|
pub os: Os,
|
||||||
|
pub network: Network,
|
||||||
|
pub packages: Packages,
|
||||||
|
pub autostart: Autostart
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Setup {
|
||||||
|
fn read<T: DeserializeOwned>(path: &Path, file: &str) -> anyhow::Result<T> {
|
||||||
|
toml::from_slice(&fs::read(path.join(file)).with_context(|| format!("Failed to read {file}"))?)
|
||||||
|
.with_context(|| format!("Failed to deserialize {file}"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load() -> anyhow::Result<Self> {
|
||||||
|
let path = PathBuf::from("setup");
|
||||||
|
let os = Self::read(&path, "os.toml")?;
|
||||||
|
let network = Self::read(&path, "network.toml")?;
|
||||||
|
let packages = Self::read(&path, "packages.toml")?;
|
||||||
|
let autostart = Self::read(&path, "autostart.toml")?;
|
||||||
|
Ok(Self {
|
||||||
|
os,
|
||||||
|
network,
|
||||||
|
packages,
|
||||||
|
autostart
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
33
src/setup/network.rs
Normal file
33
src/setup/network.rs
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct Network {
|
||||||
|
#[serde(default)]
|
||||||
|
pub tailscale: bool,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub wifi: Vec<Wifi>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
//#[serde(deny_unknown_fields)]
|
||||||
|
pub struct Wifi {
|
||||||
|
pub ssid: String,
|
||||||
|
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub security: WifiSecurity
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(tag = "security")]
|
||||||
|
pub enum WifiSecurity {
|
||||||
|
#[serde(rename = "none")]
|
||||||
|
None,
|
||||||
|
|
||||||
|
#[serde(rename = "WPA-PSK")]
|
||||||
|
WpaPsk { password: String },
|
||||||
|
|
||||||
|
#[serde(rename = "WPA-EAP")]
|
||||||
|
WpaEap { identity: String, password: String }
|
||||||
|
}
|
216
src/setup/os.rs
Normal file
216
src/setup/os.rs
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
use serde::{
|
||||||
|
de::{self, Deserializer, Visitor},
|
||||||
|
Deserialize
|
||||||
|
};
|
||||||
|
use std::{
|
||||||
|
borrow::Cow,
|
||||||
|
fmt::{self, Display, Formatter}
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct Os {
|
||||||
|
pub alpine: Alpine,
|
||||||
|
pub rpi: Rpi,
|
||||||
|
pub host: Host,
|
||||||
|
pub user: Vec<User>
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Branch {
|
||||||
|
Edge,
|
||||||
|
Version(String)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Branch {
|
||||||
|
pub fn git_branch(&self) -> Cow<'static, str> {
|
||||||
|
match self {
|
||||||
|
Self::Edge => "master".into(),
|
||||||
|
Self::Version(v) => format!("{v}-stable").into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Branch {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Version("3.17".into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for Branch {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>
|
||||||
|
{
|
||||||
|
struct BranchVisitor;
|
||||||
|
|
||||||
|
impl<'de> Visitor<'de> for BranchVisitor {
|
||||||
|
type Value = Branch;
|
||||||
|
|
||||||
|
fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "the alpine branch, either edge or a version like v3.17")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error
|
||||||
|
{
|
||||||
|
if let Some(version) = v.strip_prefix('v') {
|
||||||
|
Ok(Branch::Version(version.to_owned()))
|
||||||
|
} else if v == "edge" {
|
||||||
|
Ok(Branch::Edge)
|
||||||
|
} else {
|
||||||
|
Err(E::custom("Invalid branch, expected either edge or a version like v3.17"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_str(BranchVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Branch {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Version(v) => write!(f, "v{v}"),
|
||||||
|
Self::Edge => write!(f, "edge")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Deserialize)]
|
||||||
|
#[serde(rename_all = "lowercase")]
|
||||||
|
pub enum Arch {
|
||||||
|
ArmHf,
|
||||||
|
#[default]
|
||||||
|
ArmV7,
|
||||||
|
Aarch64
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Arch {
|
||||||
|
pub fn cbuild(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::ArmHf => "armv6-alpine-linux-musleabihf",
|
||||||
|
Self::ArmV7 => "armv7-alpine-linux-musleabihf",
|
||||||
|
Self::Aarch64 => "aarch64-alpine-linux-musl"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_str(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::ArmHf => "armhf",
|
||||||
|
Self::ArmV7 => "armv7",
|
||||||
|
Self::Aarch64 => "aarch64"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is64bit(&self) -> bool {
|
||||||
|
matches!(self, Self::Aarch64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Arch {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
f.write_str(self.to_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_mirror() -> String {
|
||||||
|
"https://dl-cdn.alpinelinux.org/alpine".into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct Alpine {
|
||||||
|
#[serde(default)]
|
||||||
|
pub branch: Branch,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub arch: Arch,
|
||||||
|
|
||||||
|
#[serde(default = "default_mirror")]
|
||||||
|
pub mirror: String,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub extra_repos: Vec<String>,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub extra_keys: Vec<String>
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_cmdline() -> String {
|
||||||
|
"dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait";
|
||||||
|
"modules=loop,squashfs,sd-mod,usb-storage root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline fsck.repair=yes console=tty1 rootwait"
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_usercfg() -> String {
|
||||||
|
r#"# modify this file instead of config.txt
|
||||||
|
|
||||||
|
# hide raspberry pi logo on startup
|
||||||
|
disable_splash=1
|
||||||
|
boot_delay=0
|
||||||
|
|
||||||
|
# enable uart / disable bluetooth
|
||||||
|
enable_uart=1
|
||||||
|
dtoverlay=disable-bt
|
||||||
|
|
||||||
|
# enable HDMI output
|
||||||
|
dtoverlay=vc4-kms-v3d
|
||||||
|
display_auto_detect=1
|
||||||
|
disable_overscan=1
|
||||||
|
"#
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct Rpi {
|
||||||
|
#[serde(default = "default_cmdline")]
|
||||||
|
pub cmdline: String,
|
||||||
|
|
||||||
|
#[serde(default = "default_usercfg")]
|
||||||
|
pub usercfg: String
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_hostname() -> String {
|
||||||
|
"alpi".into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_keymap() -> String {
|
||||||
|
"de".into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_timezone() -> String {
|
||||||
|
"Europe/Amsterdam".into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct Host {
|
||||||
|
#[serde(default = "default_hostname")]
|
||||||
|
pub hostname: String,
|
||||||
|
|
||||||
|
#[serde(default = "default_keymap")]
|
||||||
|
pub keymap: String,
|
||||||
|
pub keymap_variant: Option<String>,
|
||||||
|
|
||||||
|
#[serde(default = "default_timezone")]
|
||||||
|
pub timezone: String
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct User {
|
||||||
|
pub name: String,
|
||||||
|
|
||||||
|
pub password: Option<String>,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub sudo: bool,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub groups: Vec<String>,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub authorized_keys: Vec<String>
|
||||||
|
}
|
8
src/setup/packages.rs
Normal file
8
src/setup/packages.rs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct Packages {
|
||||||
|
pub install: Vec<String>,
|
||||||
|
pub autostart: Vec<String>
|
||||||
|
}
|
Loading…
Reference in a new issue