diff --git a/api.go b/api.go index 086ba6a8991106a4f8b4aa404367185a9d3e95c6..305d7c21306fbdcddbec0194e777bb132bf2f1ae 100644 --- a/api.go +++ b/api.go @@ -2,6 +2,8 @@ package radioai import ( "bytes" + "crypto/rand" + "encoding/base64" "encoding/json" "errors" "strings" @@ -119,3 +121,10 @@ func (r *RadioAPI) GetMasterAddr() (string, error) { } return response[0].Value, nil } + +// GeneratePassword returns a new random password. +func GeneratePassword() string { + b := make([]byte, 6) + rand.Read(b) + return base64.StdEncoding.EncodeToString(b) +} diff --git a/cmd/radioctl/radioctl.go b/cmd/radioctl/radioctl.go index c0310824c4ed3687663bc0840615de54f23fcd4b..e827fba89960f3fd8c8a1c03870578324ed7dab1 100644 --- a/cmd/radioctl/radioctl.go +++ b/cmd/radioctl/radioctl.go @@ -1,8 +1,6 @@ package main import ( - "crypto/rand" - "encoding/base64" "flag" "fmt" "hash/crc32" @@ -104,12 +102,6 @@ func generateUsername(path string) string { return fmt.Sprintf("source%d", crc32.ChecksumIEEE([]byte(path))) } -func generatePassword() string { - b := make([]byte, 6) - rand.Read(b) - return base64.StdEncoding.EncodeToString(b) -} - func createMount(args []string) { path := args[0] if !strings.HasPrefix(path, "/") { @@ -125,7 +117,7 @@ func createMount(args []string) { // Create the new mount, randomly generate source authentication. username := generateUsername(path) - password := generatePassword() + password := radioai.GeneratePassword() m := &radioai.Mount{ Name: path, Username: username, diff --git a/icecast.go b/icecast.go index 5403fc16e8cf8e4de4187c8adb4557423779ae75..a7fd495ab9929e190c16fa4fbb9ea4eeea2e60bf 100644 --- a/icecast.go +++ b/icecast.go @@ -6,16 +6,18 @@ import ( ) type IcecastController struct { - PublicIp string - ConfigFile string - InitScript string + PublicIp string + ConfigFile string + InitScript string + config *icecastConfig } func NewIcecastController(publicIp string) *IcecastController { return &IcecastController{ - PublicIp: publicIp, - ConfigFile: "/etc/icecast2/icecast.conf", - InitScript: "/etc/init.d/icecast2", + PublicIp: publicIp, + ConfigFile: "/etc/icecast2/icecast.conf", + InitScript: "/etc/init.d/icecast2", + config: newIcecastConfig(publicIp), } } @@ -31,8 +33,8 @@ func (ic *IcecastController) Update(conf *ClusterConfig, isMaster bool, masterAd tmpf := ic.ConfigFile + ".tmp" defer os.Remove(tmpf) - iconfig := NewIcecastConfig(conf, ic.PublicIp, isMaster, masterAddr) - if err := iconfig.EncodeToFile(tmpf); err != nil { + ic.config.Update(conf, isMaster, masterAddr) + if err := ic.config.EncodeToFile(tmpf); err != nil { return err } diff --git a/icecast_config.go b/icecast_config.go index 4be1860b5795b97c969809db08a0ccee2bbec0ef..776b504f369e3e618484eb2ebd7a5ca6cb9d7358 100644 --- a/icecast_config.go +++ b/icecast_config.go @@ -79,7 +79,7 @@ type iceMountConfig struct { OnDisconnect string `xml:"on-disconnect,omitempty"` } -type IcecastConfig struct { +type icecastConfig struct { XMLName xml.Name Limits iceLimitsConfig `xml:"limits"` Auth iceAuthenticationConfig `xml:"authentication"` @@ -93,11 +93,13 @@ type IcecastConfig struct { Mounts []iceMountConfig `xml:"mount"` } -func defaultDebianConfig() *IcecastConfig { - sourcePw := "x" - adminPw := "password" +func defaultDebianConfig(publicIp string) *icecastConfig { + // Pick some random passwords on startup. We don't use them, + // but icecast is happier if they're set. + sourcePw := GeneratePassword() + adminPw := GeneratePassword() - return &IcecastConfig{ + return &icecastConfig{ XMLName: xml.Name{"", "icecast"}, Limits: iceLimitsConfig{ Clients: maxClients, @@ -115,6 +117,7 @@ func defaultDebianConfig() *IcecastConfig { AdminUser: "admin", AdminPassword: adminPw, }, + Hostname: publicIp, Fileserve: 1, Paths: icePathsConfig{ Basedir: "/usr/share/icecast2", @@ -133,12 +136,14 @@ func defaultDebianConfig() *IcecastConfig { {"0.0.0.0", baseHttpPort, 0}, {"0.0.0.0", shoutHttpPort, 1}, }, - Relays: []iceRelayConfig{}, - Mounts: []iceMountConfig{}, } } -func (c *IcecastConfig) Encode() ([]byte, error) { +func newIcecastConfig(publicIp string) *icecastConfig { + return defaultDebianConfig(publicIp) +} + +func (c *icecastConfig) Encode() ([]byte, error) { var buf bytes.Buffer output, err := xml.MarshalIndent(c, "", " ") @@ -152,7 +157,7 @@ func (c *IcecastConfig) Encode() ([]byte, error) { return buf.Bytes(), nil } -func (c *IcecastConfig) EncodeToFile(path string) error { +func (c *icecastConfig) EncodeToFile(path string) error { file, err := os.Create(path) if err != nil { return err @@ -196,15 +201,20 @@ func mountToRelay(masterAddr string, m *Mount) iceRelayConfig { } } -func NewIcecastConfig(config *ClusterConfig, publicIp string, isMaster bool, masterAddr string) *IcecastConfig { - iconf := defaultDebianConfig() - iconf.Hostname = publicIp - for _, m := range config.ListMounts() { - if isMaster { - iconf.Mounts = append(iconf.Mounts, mountToConfig(m)) - } else { - iconf.Relays = append(iconf.Relays, mountToRelay(masterAddr, m)) +func (ic *icecastConfig) Update(config *ClusterConfig, isMaster bool, masterAddr string) { + ic.Mounts = nil + ic.Relays = nil + if isMaster { + mounts := make([]iceMountConfig, 0) + for _, m := range config.ListMounts() { + mounts = append(mounts, mountToConfig(m)) + } + ic.Mounts = mounts + } else { + relays := make([]iceRelayConfig, 0) + for _, m := range config.ListMounts() { + relays = append(relays, mountToRelay(masterAddr, m)) } + ic.Relays = relays } - return iconf } diff --git a/icecast_config_test.go b/icecast_config_test.go index 8c2633580c319f2a80de8486ed3b090ad2537ed5..88967483cf30dde6a7f6a8add525767c00cef14d 100644 --- a/icecast_config_test.go +++ b/icecast_config_test.go @@ -15,7 +15,8 @@ func TestIcecastConfig(t *testing.T) { c.setMount(mount) // Test a relay config. - ice := NewIcecastConfig(c, "1.2.3.4", false, "2.3.4.5") + ice := newIcecastConfig("1.2.3.4") + ice.Update(c, false, "2.3.4.5") output, err := ice.Encode() if err != nil { t.Fatal(err) @@ -29,7 +30,8 @@ func TestIcecastConfig(t *testing.T) { } // Test a master config. - ice = NewIcecastConfig(c, "1.2.3.4", true, "2.3.4.5") + ice = newIcecastConfig("1.2.3.4") + ice.Update(c, true, "2.3.4.5") output, err = ice.Encode() if err != nil { t.Fatal(err) diff --git a/node.go b/node.go index 9bfbda122f8475803d08ed00382a7c202cbb0110..36fad457d4bae584f50bd3d1531451dbe4b1afdb 100644 --- a/node.go +++ b/node.go @@ -110,7 +110,13 @@ func (w *ConfigSyncer) syncer() { continue } + // Update the 'last seen' index, so that if + // the Watcher dies, it knows where to start + // from and we do not have to download the + // full configuration again. w.index = response.Index + + // Trigger an update. trigger(w.upch) case <-w.stop: