prepare: configures snapcast server and client
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
Marvin Steadfast 2021-04-29 13:41:37 +02:00
parent 979040227e
commit 9af55ee991
3 changed files with 156 additions and 48 deletions

View File

@ -8,3 +8,5 @@ tmpfs /var/lib/systemd/timesync tmpfs auto,noatime,size=5m,mode=0755
tmpfs /var/cache/mopidy tmpfs auto,noatime,size=5m,mode=0755,uid={{.MopidyUID}},gid={{.MopidyGID}} 0 0 tmpfs /var/cache/mopidy tmpfs auto,noatime,size=5m,mode=0755,uid={{.MopidyUID}},gid={{.MopidyGID}} 0 0
tmpfs /var/cache/upmpdcli tmpfs auto,noatime,size=5m,mode=0755,uid={{.UpmpdcliUID}},gid={{.UpmpdcliGID}} 0 0 tmpfs /var/cache/upmpdcli tmpfs auto,noatime,size=5m,mode=0755,uid={{.UpmpdcliUID}},gid={{.UpmpdcliGID}} 0 0
tmpfs /var/lib/ntp tmpfs nosuid,nodev 0 0 tmpfs /var/lib/ntp tmpfs nosuid,nodev 0 0
tmpfs /var/lib/snapserver tmpfs nosuid,nodev 0 0
tmpfs /var/lib/snapclient tmpfs nosuid,nodev 0 0

View File

@ -3,7 +3,7 @@ cache_dir = /var/cache/mopidy
config_dir = /etc/mopidy/ config_dir = /etc/mopidy/
[audio] [audio]
output = alsasink output = audioresample ! audioconvert ! audio/x-raw,rate=48000,channels=2,format=S16LE ! filesink location=/tmp/snapfifo
mixer = alsamixer mixer = alsamixer
mixer_volume = 100 mixer_volume = 100
@ -11,7 +11,6 @@ mixer_volume = 100
card = 0 card = 0
control= Headphone control= Headphone
[mpd] [mpd]
hostname = 0.0.0.0 hostname = 0.0.0.0

View File

@ -27,6 +27,10 @@ const (
schnutboxConfigDir = "/etc/schnutibox" schnutboxConfigDir = "/etc/schnutibox"
upmpdcliUser = "upmpdcli" upmpdcliUser = "upmpdcli"
upmpdcliGroup = "nogroup" upmpdcliGroup = "nogroup"
snapserverUser = "snapserver"
snapserverGroup = "snapserver"
snapclientUser = "snapclient"
snapclientGroup = "snapclient"
) )
var Cfg = struct { var Cfg = struct {
@ -41,11 +45,11 @@ var Cfg = struct {
System string System string
}{} }{}
// BoxService creates a systemd service for schnutibox. // boxService creates a systemd service for schnutibox.
func BoxService(filename string, enable bool) error { func boxService(filename string, enable bool) error {
logger := log.With().Str("stage", "BoxService").Logger() logger := log.With().Str("stage", "BoxService").Logger()
if err := CreateUser(); err != nil { if err := createUser(); err != nil {
return fmt.Errorf("could not create user: %w", err) return fmt.Errorf("could not create user: %w", err)
} }
@ -83,7 +87,7 @@ func BoxService(filename string, enable bool) error {
return nil return nil
} }
func NTP() error { func ntp() error {
logger := log.With().Str("stage", "NTP").Logger() logger := log.With().Str("stage", "NTP").Logger()
cmd := exec.Command("apt-get", "install", "-y", "ntp", "ntpdate") cmd := exec.Command("apt-get", "install", "-y", "ntp", "ntpdate")
@ -119,9 +123,9 @@ func NTP() error {
return nil return nil
} }
// Fstab creates a fstab for a read-only system. // fstab creates a fstab for a read-only system.
// nolint:funlen // nolint:funlen
func Fstab(system string) error { func fstab(system string) error {
logger := log.With().Str("stage", "Fstab").Logger() logger := log.With().Str("stage", "Fstab").Logger()
// Getting timesync user and group informations. // Getting timesync user and group informations.
@ -163,6 +167,31 @@ func Fstab(system string) error {
logger.Debug().Str("uid", upmpdcliUser.Uid).Str("gid", upmpdcliGroup.Gid).Msg("upmpdcli") logger.Debug().Str("uid", upmpdcliUser.Uid).Str("gid", upmpdcliGroup.Gid).Msg("upmpdcli")
// Getting snapserver user and group informations.
snapserverUser, err := user.Lookup(snapserverUser)
if err != nil {
return fmt.Errorf("could not lookup snapserver user: %w", err)
}
snapserverGroup, err := user.LookupGroup(snapserverGroup)
if err != nil {
return fmt.Errorf("could not lookup snapserver group: %w", err)
}
logger.Debug().Str("uid", snapserverUser.Uid).Str("gid", snapserverGroup.Gid).Msg("snapserver")
snapclientUser, err := user.Lookup(snapclientUser)
if err != nil {
return fmt.Errorf("could not lookup snapclient user: %w", err)
}
snapclientGroup, err := user.LookupGroup(snapclientGroup)
if err != nil {
return fmt.Errorf("could not lookup snapclient group: %w", err)
}
logger.Debug().Str("uid", snapclientUser.Uid).Str("gid", snapclientGroup.Gid).Msg("snapclient")
// Chose the right template. // Chose the right template.
// In future it should be a switch statement. // In future it should be a switch statement.
tmpl, err := assets.Assets.ReadFile("templates/fstab.raspbian.tmpl") tmpl, err := assets.Assets.ReadFile("templates/fstab.raspbian.tmpl")
@ -188,6 +217,10 @@ func Fstab(system string) error {
MopidyGID string MopidyGID string
UpmpdcliUID string UpmpdcliUID string
UpmpdcliGID string UpmpdcliGID string
SnapserverUID string
SnapserverGID string
SnapclientUID string
SnapclientGID string
}{ }{
timesyncUser.Uid, timesyncUser.Uid,
timesyncGroup.Gid, timesyncGroup.Gid,
@ -195,6 +228,10 @@ func Fstab(system string) error {
mopidyGroup.Gid, mopidyGroup.Gid,
upmpdcliUser.Uid, upmpdcliUser.Uid,
upmpdcliGroup.Gid, upmpdcliGroup.Gid,
snapserverUser.Uid,
snapserverGroup.Gid,
snapclientUser.Uid,
snapclientGroup.Gid,
}); err != nil { }); err != nil {
return fmt.Errorf("could not write templated fstab: %w", err) return fmt.Errorf("could not write templated fstab: %w", err)
} }
@ -202,8 +239,8 @@ func Fstab(system string) error {
return nil return nil
} }
// RemovePkgs removes not needed software in read-only mode. // removePkgs removes not needed software in read-only mode.
func RemovePkgs(system string) error { func removePkgs(system string) error {
logger := log.With().Str("stage", "RemovePkgs").Logger() logger := log.With().Str("stage", "RemovePkgs").Logger()
if system != "raspbian" { if system != "raspbian" {
logger.Info().Msg("nothing to do") logger.Info().Msg("nothing to do")
@ -240,7 +277,7 @@ func RemovePkgs(system string) error {
return nil return nil
} }
func CreateUDEVrules() error { func udevRules() error {
logger := log.With().Str("stage", "CreateUDEVrules").Logger() logger := log.With().Str("stage", "CreateUDEVrules").Logger()
logger.Info().Msg("writing udev rule file") logger.Info().Msg("writing udev rule file")
@ -271,8 +308,8 @@ func CreateUDEVrules() error {
return nil return nil
} }
// CreateUser creates schnutibox system user and group. // createUser creates schnutibox system user and group.
func CreateUser() error { func createUser() error {
logger := log.With().Str("stage", "CreateUser").Logger() logger := log.With().Str("stage", "CreateUser").Logger()
cmd := exec.Command("adduser", "--system", "--group", "--no-create-home", schnutiboxUser) cmd := exec.Command("adduser", "--system", "--group", "--no-create-home", schnutiboxUser)
@ -285,8 +322,8 @@ func CreateUser() error {
return nil return nil
} }
// CreateSymlinks creates all needed symlinks. // symlinks creates all needed symlinks.
func CreateSymlinks(system string) error { func symlinks(system string) error {
logger := log.With().Str("stage", "Symlinks").Logger() logger := log.With().Str("stage", "Symlinks").Logger()
links := []struct { links := []struct {
@ -365,17 +402,17 @@ func cmdlineTxt() error {
return nil return nil
} }
// makeReadOnly executes stuff if a read-only system is wanted. // readOnly executes stuff if a read-only system is wanted.
func makeReadOnly(system string) error { func readOnly(system string) error {
if err := RemovePkgs(system); err != nil { if err := removePkgs(system); err != nil {
return fmt.Errorf("could not remove pkgs: %w", err) return fmt.Errorf("could not remove pkgs: %w", err)
} }
if err := CreateSymlinks(system); err != nil { if err := symlinks(system); err != nil {
return fmt.Errorf("could not create symlinks: %w", err) return fmt.Errorf("could not create symlinks: %w", err)
} }
if err := Fstab(system); err != nil { if err := fstab(system); err != nil {
return fmt.Errorf("could not create fstab: %w", err) return fmt.Errorf("could not create fstab: %w", err)
} }
@ -386,9 +423,9 @@ func makeReadOnly(system string) error {
return nil return nil
} }
// Mopidy setups mopidy. // mopidy setups mopidy.
//nolint:funlen,cyclop //nolint:funlen,cyclop
func Mopidy() error { func mopidy() error {
logger := log.With().Str("stage", "Mopidy").Logger() logger := log.With().Str("stage", "Mopidy").Logger()
// GPG Key. // GPG Key.
@ -501,7 +538,7 @@ func Mopidy() error {
// Upmpdcli setups upmpdcli. // Upmpdcli setups upmpdcli.
//nolint:funlen //nolint:funlen
func Upmpdcli() error { func upmpdcli() error {
logger := log.With().Str("stage", "Upmpdcli").Logger() logger := log.With().Str("stage", "Upmpdcli").Logger()
// GPG Key. // GPG Key.
@ -584,8 +621,73 @@ func Upmpdcli() error {
return nil return nil
} }
func SchnutiboxConfig() error { // nolint:funlen
logger := log.With().Str("stage", "Upmpdcli").Logger() func snapcast() error {
logger := log.With().Str("stage", "snapcast").Logger()
// Download deb.
cmd := exec.Command(
"wget",
"https://github.com/badaix/snapcast/releases/download/v0.24.0/snapclient_0.24.0-1_without-pulse_armhf.deb",
"-O", "/tmp/snapclient.deb",
)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
logger.Debug().Str("cmd", cmd.String()).Msg("running")
if err := cmd.Run(); err != nil {
return fmt.Errorf("could not download snapclient deb: %w", err)
}
// Install deb
cmd = exec.Command(
"/bin/sh", "-c",
"dpkg -i /tmp/snapclient.deb; apt --fix-broken install -y; rm /tmp/snapclient.deb",
)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
logger.Debug().Str("cmd", cmd.String()).Msg("running")
if err := cmd.Run(); err != nil {
return fmt.Errorf("could not install snapclient deb: %w", err)
}
// Download deb.
cmd = exec.Command(
"wget",
"https://github.com/badaix/snapcast/releases/download/v0.24.0/snapserver_0.24.0-1_armhf.deb",
"-O", "/tmp/snapserver.deb",
)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
logger.Debug().Str("cmd", cmd.String()).Msg("running")
if err := cmd.Run(); err != nil {
return fmt.Errorf("could not download snapserver deb: %w", err)
}
// Install deb
cmd = exec.Command(
"/bin/sh", "-c",
"dpkg -i /tmp/snapserver.deb; apt --fix-broken install -y; rm /tmp/snapserver.deb",
)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
logger.Debug().Str("cmd", cmd.String()).Msg("running")
if err := cmd.Run(); err != nil {
return fmt.Errorf("could not install snapserver deb: %w", err)
}
return nil
}
func schnutiboxConfig() error {
logger := log.With().Str("stage", "schnutiboxConfig").Logger()
logger.Info().Msg("writing schnutibox config") logger.Info().Msg("writing schnutibox config")
// Parse template. // Parse template.
@ -615,38 +717,43 @@ func Run(cmd *cobra.Command, args []string) {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}) log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
// Install schnutibox service. // Install schnutibox service.
if err := BoxService(serviceLocation+"/"+serviceFileName, true); err != nil { if err := boxService(serviceLocation+"/"+serviceFileName, true); err != nil {
log.Fatal().Err(err).Msg("could not create schnutibox service") log.Fatal().Err(err).Msg("could not create schnutibox service")
} }
// Create schnutibox config. // Create schnutibox config.
if err := SchnutiboxConfig(); err != nil { if err := schnutiboxConfig(); err != nil {
log.Fatal().Err(err).Msg("could not create schnutibox config.") log.Fatal().Err(err).Msg("could not create schnutibox config.")
} }
// Install udev file. // Install udev file.
if err := CreateUDEVrules(); err != nil { if err := udevRules(); err != nil {
log.Fatal().Err(err).Msg("could not install udev rules") log.Fatal().Err(err).Msg("could not install udev rules")
} }
// Setup NTP. // Setup NTP.
if err := NTP(); err != nil { if err := ntp(); err != nil {
log.Fatal().Err(err).Msg("could not setup ntp") log.Fatal().Err(err).Msg("could not setup ntp")
} }
// Setup mopidy. // Setup mopidy.
if err := Mopidy(); err != nil { if err := mopidy(); err != nil {
log.Fatal().Err(err).Msg("could not setup mopidy") log.Fatal().Err(err).Msg("could not setup mopidy")
} }
// Setup upmpdcli. // Setup upmpdcli.
if err := Upmpdcli(); err != nil { if err := upmpdcli(); err != nil {
log.Fatal().Err(err).Msg("could not setup upmpdcli") log.Fatal().Err(err).Msg("could not setup upmpdcli")
} }
// Setup snapcast.
if err := snapcast(); err != nil {
log.Fatal().Err(err).Msg("could not setup snapclient")
}
// Making system read-only. // Making system read-only.
if Cfg.ReadOnly { if Cfg.ReadOnly {
if err := makeReadOnly(Cfg.System); err != nil { if err := readOnly(Cfg.System); err != nil {
log.Fatal().Err(err).Msg("could not make system read-only") log.Fatal().Err(err).Msg("could not make system read-only")
} }
} }