Merge pull request #532 from AudriusButkevicius/config

Replace NodeConfiguration with RepositoryNodeConfiguration (Fixes #522)
This commit is contained in:
Audrius Butkevicius 2014-08-17 12:47:12 +01:00
commit 52219c5f3f
3 changed files with 85 additions and 23 deletions

View File

@ -303,7 +303,7 @@ func main() {
{ {
ID: "default", ID: "default",
Directory: defaultRepo, Directory: defaultRepo,
Nodes: []config.NodeConfiguration{{NodeID: myID}}, Nodes: []config.RepositoryNodeConfiguration{{NodeID: myID}},
}, },
} }
cfg.Nodes = []config.NodeConfiguration{ cfg.Nodes = []config.NodeConfiguration{

View File

@ -31,13 +31,13 @@ type Configuration struct {
} }
type RepositoryConfiguration struct { type RepositoryConfiguration struct {
ID string `xml:"id,attr"` ID string `xml:"id,attr"`
Directory string `xml:"directory,attr"` Directory string `xml:"directory,attr"`
Nodes []NodeConfiguration `xml:"node"` Nodes []RepositoryNodeConfiguration `xml:"node"`
ReadOnly bool `xml:"ro,attr"` ReadOnly bool `xml:"ro,attr"`
IgnorePerms bool `xml:"ignorePerms,attr"` IgnorePerms bool `xml:"ignorePerms,attr"`
Invalid string `xml:"-"` // Set at runtime when there is an error, not saved Invalid string `xml:"-"` // Set at runtime when there is an error, not saved
Versioning VersioningConfiguration `xml:"versioning"` Versioning VersioningConfiguration `xml:"versioning"`
nodeIDs []protocol.NodeID nodeIDs []protocol.NodeID
} }
@ -100,6 +100,13 @@ type NodeConfiguration struct {
CertName string `xml:"certName,attr,omitempty"` CertName string `xml:"certName,attr,omitempty"`
} }
type RepositoryNodeConfiguration struct {
NodeID protocol.NodeID `xml:"id,attr"`
Deprecated_Name string `xml:"name,attr,omitempty" json:"-"`
Deprecated_Addresses []string `xml:"address,omitempty" json:"-"`
}
type OptionsConfiguration struct { type OptionsConfiguration struct {
ListenAddress []string `xml:"listenAddress" default:"0.0.0.0:22000"` ListenAddress []string `xml:"listenAddress" default:"0.0.0.0:22000"`
GlobalAnnServer string `xml:"globalAnnounceServer" default:"announce.syncthing.net:22026"` GlobalAnnServer string `xml:"globalAnnounceServer" default:"announce.syncthing.net:22026"`
@ -311,6 +318,11 @@ func Load(rd io.Reader, myID protocol.NodeID) (Configuration, error) {
convertV2V3(&cfg) convertV2V3(&cfg)
} }
// Upgrade to v4 configuration if appropriate
if cfg.Version == 3 {
convertV3V4(&cfg)
}
// Hash old cleartext passwords // Hash old cleartext passwords
if len(cfg.GUI.Password) > 0 && cfg.GUI.Password[0] != '$' { if len(cfg.GUI.Password) > 0 && cfg.GUI.Password[0] != '$' {
hash, err := bcrypt.GenerateFromPassword([]byte(cfg.GUI.Password), 0) hash, err := bcrypt.GenerateFromPassword([]byte(cfg.GUI.Password), 0)
@ -329,15 +341,22 @@ func Load(rd io.Reader, myID protocol.NodeID) (Configuration, error) {
} }
// Ensure this node is present in all relevant places // Ensure this node is present in all relevant places
me := cfg.GetNodeConfiguration(myID)
if me == nil {
myName, _ := os.Hostname()
cfg.Nodes = append(cfg.Nodes, NodeConfiguration{
NodeID: myID,
Name: myName,
})
}
sort.Sort(NodeConfigurationList(cfg.Nodes))
// Ensure that any loose nodes are not present in the wrong places // Ensure that any loose nodes are not present in the wrong places
// Ensure that there are no duplicate nodes // Ensure that there are no duplicate nodes
cfg.Nodes = ensureNodePresent(cfg.Nodes, myID)
sort.Sort(NodeConfigurationList(cfg.Nodes))
for i := range cfg.Repositories { for i := range cfg.Repositories {
cfg.Repositories[i].Nodes = ensureNodePresent(cfg.Repositories[i].Nodes, myID) cfg.Repositories[i].Nodes = ensureNodePresent(cfg.Repositories[i].Nodes, myID)
cfg.Repositories[i].Nodes = ensureExistingNodes(cfg.Repositories[i].Nodes, existingNodes) cfg.Repositories[i].Nodes = ensureExistingNodes(cfg.Repositories[i].Nodes, existingNodes)
cfg.Repositories[i].Nodes = ensureNoDuplicates(cfg.Repositories[i].Nodes) cfg.Repositories[i].Nodes = ensureNoDuplicates(cfg.Repositories[i].Nodes)
sort.Sort(NodeConfigurationList(cfg.Repositories[i].Nodes)) sort.Sort(RepositoryNodeConfigurationList(cfg.Repositories[i].Nodes))
} }
// An empty address list is equivalent to a single "dynamic" entry // An empty address list is equivalent to a single "dynamic" entry
@ -351,6 +370,21 @@ func Load(rd io.Reader, myID protocol.NodeID) (Configuration, error) {
return cfg, err return cfg, err
} }
func convertV3V4(cfg *Configuration) {
// In previous versions, repositories held full node configurations.
// Since that's the only place where node configs were in V1, we still have
// to define the deprecated fields to be able to upgrade from V1 to V4.
for i, repo := range cfg.Repositories {
for j := range repo.Nodes {
rncfg := cfg.Repositories[i].Nodes[j]
rncfg.Deprecated_Name = ""
rncfg.Deprecated_Addresses = nil
}
}
cfg.Version = 4
}
func convertV2V3(cfg *Configuration) { func convertV2V3(cfg *Configuration) {
// In previous versions, compression was always on. When upgrading, enable // In previous versions, compression was always on. When upgrading, enable
// compression on all existing new. New nodes will get compression on by // compression on all existing new. New nodes will get compression on by
@ -372,7 +406,7 @@ func convertV1V2(cfg *Configuration) {
// Collect the list of nodes. // Collect the list of nodes.
// Replace node configs inside repositories with only a reference to the nide ID. // Replace node configs inside repositories with only a reference to the nide ID.
// Set all repositories to read only if the global read only flag is set. // Set all repositories to read only if the global read only flag is set.
var nodes = map[string]NodeConfiguration{} var nodes = map[string]RepositoryNodeConfiguration{}
for i, repo := range cfg.Repositories { for i, repo := range cfg.Repositories {
cfg.Repositories[i].ReadOnly = cfg.Options.Deprecated_ReadOnly cfg.Repositories[i].ReadOnly = cfg.Options.Deprecated_ReadOnly
for j, node := range repo.Nodes { for j, node := range repo.Nodes {
@ -380,14 +414,18 @@ func convertV1V2(cfg *Configuration) {
if _, ok := nodes[id]; !ok { if _, ok := nodes[id]; !ok {
nodes[id] = node nodes[id] = node
} }
cfg.Repositories[i].Nodes[j] = NodeConfiguration{NodeID: node.NodeID} cfg.Repositories[i].Nodes[j] = RepositoryNodeConfiguration{NodeID: node.NodeID}
} }
} }
cfg.Options.Deprecated_ReadOnly = false cfg.Options.Deprecated_ReadOnly = false
// Set and sort the list of nodes. // Set and sort the list of nodes.
for _, node := range nodes { for _, node := range nodes {
cfg.Nodes = append(cfg.Nodes, node) cfg.Nodes = append(cfg.Nodes, NodeConfiguration{
NodeID: node.NodeID,
Name: node.Deprecated_Name,
Addresses: node.Deprecated_Addresses,
})
} }
sort.Sort(NodeConfigurationList(cfg.Nodes)) sort.Sort(NodeConfigurationList(cfg.Nodes))
@ -412,23 +450,33 @@ func (l NodeConfigurationList) Len() int {
return len(l) return len(l)
} }
func ensureNodePresent(nodes []NodeConfiguration, myID protocol.NodeID) []NodeConfiguration { type RepositoryNodeConfigurationList []RepositoryNodeConfiguration
func (l RepositoryNodeConfigurationList) Less(a, b int) bool {
return l[a].NodeID.Compare(l[b].NodeID) == -1
}
func (l RepositoryNodeConfigurationList) Swap(a, b int) {
l[a], l[b] = l[b], l[a]
}
func (l RepositoryNodeConfigurationList) Len() int {
return len(l)
}
func ensureNodePresent(nodes []RepositoryNodeConfiguration, myID protocol.NodeID) []RepositoryNodeConfiguration {
for _, node := range nodes { for _, node := range nodes {
if node.NodeID.Equals(myID) { if node.NodeID.Equals(myID) {
return nodes return nodes
} }
} }
name, _ := os.Hostname() nodes = append(nodes, RepositoryNodeConfiguration{
nodes = append(nodes, NodeConfiguration{
NodeID: myID, NodeID: myID,
Name: name,
}) })
return nodes return nodes
} }
func ensureExistingNodes(nodes []NodeConfiguration, existingNodes map[protocol.NodeID]bool) []NodeConfiguration { func ensureExistingNodes(nodes []RepositoryNodeConfiguration, existingNodes map[protocol.NodeID]bool) []RepositoryNodeConfiguration {
count := len(nodes) count := len(nodes)
i := 0 i := 0
loop: loop:
@ -443,7 +491,7 @@ loop:
return nodes[0:count] return nodes[0:count]
} }
func ensureNoDuplicates(nodes []NodeConfiguration) []NodeConfiguration { func ensureNoDuplicates(nodes []RepositoryNodeConfiguration) []RepositoryNodeConfiguration {
count := len(nodes) count := len(nodes)
i := 0 i := 0
seenNodes := make(map[protocol.NodeID]bool) seenNodes := make(map[protocol.NodeID]bool)

View File

@ -106,7 +106,21 @@ func TestNodeConfig(t *testing.T) {
</node> </node>
</configuration>`) </configuration>`)
for i, data := range [][]byte{v1data, v2data, v3data} { v4data := []byte(`
<configuration version="4">
<repository id="test" directory="~/Sync" ro="true" ignorePerms="false">
<node id="AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR"></node>
<node id="P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2"></node>
</repository>
<node id="AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR" name="node one" compression="true">
<address>a</address>
</node>
<node id="P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2" name="node two" compression="true">
<address>b</address>
</node>
</configuration>`)
for i, data := range [][]byte{v1data, v2data, v3data, v4data} {
cfg, err := Load(bytes.NewReader(data), node1) cfg, err := Load(bytes.NewReader(data), node1)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@ -116,7 +130,7 @@ func TestNodeConfig(t *testing.T) {
{ {
ID: "test", ID: "test",
Directory: "~/Sync", Directory: "~/Sync",
Nodes: []NodeConfiguration{{NodeID: node1}, {NodeID: node4}}, Nodes: []RepositoryNodeConfiguration{{NodeID: node1}, {NodeID: node4}},
ReadOnly: true, ReadOnly: true,
}, },
} }
@ -136,7 +150,7 @@ func TestNodeConfig(t *testing.T) {
} }
expectedNodeIDs := []protocol.NodeID{node1, node4} expectedNodeIDs := []protocol.NodeID{node1, node4}
if cfg.Version != 3 { if cfg.Version != 4 {
t.Errorf("%d: Incorrect version %d != 3", i, cfg.Version) t.Errorf("%d: Incorrect version %d != 3", i, cfg.Version)
} }
if !reflect.DeepEqual(cfg.Repositories, expectedRepos) { if !reflect.DeepEqual(cfg.Repositories, expectedRepos) {