mirror of
https://github.com/octoleo/syncthing.git
synced 2024-12-22 10:58:57 +00:00
Merge pull request #2084 from calmh/norestart
Add devices without restart (fixes #2083)
This commit is contained in:
commit
de89d7a976
@ -82,8 +82,6 @@ type FolderConfiguration struct {
|
||||
IgnoreDelete bool `xml:"ignoreDelete" json:"ignoreDelete"`
|
||||
|
||||
Invalid string `xml:"-" json:"invalid"` // Set at runtime when there is an error, not saved
|
||||
|
||||
deviceIDs []protocol.DeviceID
|
||||
}
|
||||
|
||||
func (f FolderConfiguration) Copy() FolderConfiguration {
|
||||
@ -144,12 +142,11 @@ func (f *FolderConfiguration) HasMarker() bool {
|
||||
}
|
||||
|
||||
func (f *FolderConfiguration) DeviceIDs() []protocol.DeviceID {
|
||||
if f.deviceIDs == nil {
|
||||
for _, n := range f.Devices {
|
||||
f.deviceIDs = append(f.deviceIDs, n.DeviceID)
|
||||
}
|
||||
deviceIDs := make([]protocol.DeviceID, len(f.Devices))
|
||||
for i, n := range f.Devices {
|
||||
deviceIDs[i] = n.DeviceID
|
||||
}
|
||||
return f.deviceIDs
|
||||
return deviceIDs
|
||||
}
|
||||
|
||||
type VersioningConfiguration struct {
|
||||
|
@ -691,14 +691,7 @@ func (m *Model) Close(device protocol.DeviceID, err error) {
|
||||
|
||||
conn, ok := m.rawConn[device]
|
||||
if ok {
|
||||
if conn, ok := conn.(*tls.Conn); ok {
|
||||
// If the underlying connection is a *tls.Conn, Close() does more
|
||||
// than it says on the tin. Specifically, it sends a TLS alert
|
||||
// message, which might block forever if the connection is dead
|
||||
// and we don't have a deadline site.
|
||||
conn.SetWriteDeadline(time.Now().Add(250 * time.Millisecond))
|
||||
}
|
||||
conn.Close()
|
||||
closeRawConn(conn)
|
||||
}
|
||||
delete(m.protoConn, device)
|
||||
delete(m.rawConn, device)
|
||||
@ -1732,30 +1725,132 @@ func (m *Model) VerifyConfiguration(from, to config.Configuration) error {
|
||||
func (m *Model) CommitConfiguration(from, to config.Configuration) bool {
|
||||
// TODO: This should not use reflect, and should take more care to try to handle stuff without restart.
|
||||
|
||||
// Adding, removing or changing folders requires restart
|
||||
if !reflect.DeepEqual(from.Folders, to.Folders) {
|
||||
return false
|
||||
// Go through the folder configs and figure out if we need to restart or not.
|
||||
|
||||
fromFolders := mapFolders(from.Folders)
|
||||
toFolders := mapFolders(to.Folders)
|
||||
for folderID := range toFolders {
|
||||
if _, ok := fromFolders[folderID]; !ok {
|
||||
// A folder was added. Requires restart.
|
||||
if debug {
|
||||
l.Debugln(m, "requires restart, adding folder", folderID)
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
for folderID, fromCfg := range fromFolders {
|
||||
toCfg, ok := toFolders[folderID]
|
||||
if !ok {
|
||||
// A folder was removed. Requires restart.
|
||||
if debug {
|
||||
l.Debugln(m, "requires restart, removing folder", folderID)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// This folder exists on both sides. Compare the device lists, as we
|
||||
// can handle adding a device (but not currently removing one).
|
||||
|
||||
fromDevs := mapDevices(fromCfg.DeviceIDs())
|
||||
toDevs := mapDevices(toCfg.DeviceIDs())
|
||||
for dev := range fromDevs {
|
||||
if _, ok := toDevs[dev]; !ok {
|
||||
// A device was removed. Requires restart.
|
||||
if debug {
|
||||
l.Debugln(m, "requires restart, removing device", dev, "from folder", folderID)
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
for dev := range toDevs {
|
||||
if _, ok := fromDevs[dev]; !ok {
|
||||
// A device was added. Handle it!
|
||||
|
||||
m.fmut.Lock()
|
||||
m.pmut.Lock()
|
||||
|
||||
m.folderCfgs[folderID] = toCfg
|
||||
m.folderDevices[folderID] = append(m.folderDevices[folderID], dev)
|
||||
m.deviceFolders[dev] = append(m.deviceFolders[dev], folderID)
|
||||
|
||||
// If we already have a connection to this device, we should
|
||||
// disconnect it so that we start sharing the folder with it.
|
||||
// We close the underlying connection and let the normal error
|
||||
// handling kick in to clean up and reconnect.
|
||||
if conn, ok := m.rawConn[dev]; ok {
|
||||
closeRawConn(conn)
|
||||
}
|
||||
|
||||
m.pmut.Unlock()
|
||||
m.fmut.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// Check if anything else differs, apart from the device list.
|
||||
fromCfg.Devices = nil
|
||||
toCfg.Devices = nil
|
||||
if !reflect.DeepEqual(fromCfg, toCfg) {
|
||||
if debug {
|
||||
l.Debugln(m, "requires restart, folder", folderID, "configuration differs")
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Removing a device requres restart
|
||||
toDevs := make(map[protocol.DeviceID]bool, len(from.Devices))
|
||||
for _, dev := range to.Devices {
|
||||
toDevs[dev.DeviceID] = true
|
||||
}
|
||||
toDevs := mapDeviceCfgs(from.Devices)
|
||||
for _, dev := range from.Devices {
|
||||
if _, ok := toDevs[dev.DeviceID]; !ok {
|
||||
if debug {
|
||||
l.Debugln(m, "requires restart, device", dev.DeviceID, "was removed")
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// All of the generic options require restart
|
||||
if !reflect.DeepEqual(from.Options, to.Options) {
|
||||
if debug {
|
||||
l.Debugln(m, "requires restart, options differ")
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// mapFolders returns a map of folder ID to folder configuration for the given
|
||||
// slice of folder configurations.
|
||||
func mapFolders(folders []config.FolderConfiguration) map[string]config.FolderConfiguration {
|
||||
m := make(map[string]config.FolderConfiguration, len(folders))
|
||||
for _, cfg := range folders {
|
||||
m[cfg.ID] = cfg
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// mapDevices returns a map of device ID to nothing for the given slice of
|
||||
// device IDs.
|
||||
func mapDevices(devices []protocol.DeviceID) map[protocol.DeviceID]struct{} {
|
||||
m := make(map[protocol.DeviceID]struct{}, len(devices))
|
||||
for _, dev := range devices {
|
||||
m[dev] = struct{}{}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// mapDeviceCfgs returns a map of device ID to nothing for the given slice of
|
||||
// device configurations.
|
||||
func mapDeviceCfgs(devices []config.DeviceConfiguration) map[protocol.DeviceID]struct{} {
|
||||
m := make(map[protocol.DeviceID]struct{}, len(devices))
|
||||
for _, dev := range devices {
|
||||
m[dev.DeviceID] = struct{}{}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func filterIndex(folder string, fs []protocol.FileInfo, dropDeletes bool) []protocol.FileInfo {
|
||||
for i := 0; i < len(fs); {
|
||||
if fs[i].Flags&^protocol.FlagsAll != 0 {
|
||||
@ -1816,3 +1911,14 @@ func getChunk(data []string, skip, get int) ([]string, int, int) {
|
||||
}
|
||||
return data[skip : skip+get], 0, 0
|
||||
}
|
||||
|
||||
func closeRawConn(conn io.Closer) error {
|
||||
if conn, ok := conn.(*tls.Conn); ok {
|
||||
// If the underlying connection is a *tls.Conn, Close() does more
|
||||
// than it says on the tin. Specifically, it sends a TLS alert
|
||||
// message, which might block forever if the connection is dead
|
||||
// and we don't have a deadline set.
|
||||
conn.SetWriteDeadline(time.Now().Add(250 * time.Millisecond))
|
||||
}
|
||||
return conn.Close()
|
||||
}
|
||||
|
@ -63,6 +63,10 @@ func NewProcess(addr string) *Process {
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *Process) ID() protocol.DeviceID {
|
||||
return p.id
|
||||
}
|
||||
|
||||
// LogTo creates the specified log file and ensures that stdout and stderr
|
||||
// from the Start()ed process is redirected there. Must be called before
|
||||
// Start().
|
||||
@ -229,6 +233,34 @@ func (p *Process) RescanDelay(folder string, delaySeconds int) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *Process) ConfigInSync() (bool, error) {
|
||||
bs, err := p.Get("/rest/system/config/insync")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return bytes.Contains(bs, []byte("true")), nil
|
||||
}
|
||||
|
||||
func (p *Process) GetConfig() (config.Configuration, error) {
|
||||
var cfg config.Configuration
|
||||
bs, err := p.Get("/rest/system/config")
|
||||
if err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(bs, &cfg)
|
||||
return cfg, err
|
||||
}
|
||||
|
||||
func (p *Process) PostConfig(cfg config.Configuration) error {
|
||||
buf := new(bytes.Buffer)
|
||||
if err := json.NewEncoder(buf).Encode(cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := p.Post("/rest/system/config", buf)
|
||||
return err
|
||||
}
|
||||
|
||||
func InSync(folder string, ps ...*Process) bool {
|
||||
for _, p := range ps {
|
||||
p.eventMut.Lock()
|
||||
|
2
test/.gitignore
vendored
2
test/.gitignore
vendored
@ -1,6 +1,7 @@
|
||||
s1
|
||||
s2
|
||||
s3
|
||||
s4
|
||||
s12-1
|
||||
s12-2
|
||||
s23-2
|
||||
@ -20,3 +21,4 @@ h*/index*
|
||||
panic-*.log
|
||||
audit-*.log
|
||||
h*/config.xml.v*
|
||||
h*/config.xml.orig
|
||||
|
@ -3,6 +3,7 @@
|
||||
<device id="I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU"></device>
|
||||
<device id="JMFJCXB-GZDE4BN-OCJE3VF-65GYZNU-AIVJRET-3J6HMRQ-AUQIGJO-FKNHMQU"></device>
|
||||
<device id="373HSRP-QLPNLIE-JYKZVQF-P4PKZ63-R2ZE6K3-YD442U2-JHBGBQG-WWXAHAU"></device>
|
||||
<device id="7PBCTLL-JJRYBSA-MOWZRKL-MSDMN4N-4US4OMX-SYEXUS4-HSBGNRY-CZXRXAT"></device>
|
||||
<versioning></versioning>
|
||||
<lenientMtimes>false</lenientMtimes>
|
||||
<copiers>1</copiers>
|
||||
@ -31,6 +32,9 @@
|
||||
<device id="373HSRP-QLPNLIE-JYKZVQF-P4PKZ63-R2ZE6K3-YD442U2-JHBGBQG-WWXAHAU" name="s3" compression="metadata" introducer="false">
|
||||
<address>127.0.0.1:22003</address>
|
||||
</device>
|
||||
<device id="7PBCTLL-JJRYBSA-MOWZRKL-MSDMN4N-4US4OMX-SYEXUS4-HSBGNRY-CZXRXAT" name="s4" compression="metadata" introducer="false">
|
||||
<address>127.0.0.1:22004</address>
|
||||
</device>
|
||||
<gui enabled="true" tls="false">
|
||||
<address>127.0.0.1:8081</address>
|
||||
<user>testuser</user>
|
||||
|
23
test/h4/cert.pem
Normal file
23
test/h4/cert.pem
Normal file
@ -0,0 +1,23 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID6TCCAlGgAwIBAgIISz5XufRr9xMwDQYJKoZIhvcNAQELBQAwFDESMBAGA1UE
|
||||
AxMJc3luY3RoaW5nMB4XDTE1MDcyMjA3MDIzOFoXDTQ5MTIzMTIzNTk1OVowFDES
|
||||
MBAGA1UEAxMJc3luY3RoaW5nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKC
|
||||
AYEA4nE2FPVQkfMStJms0SUEjSi5qUC4I2+aCFD+q6rLJHhgzdvjXoQ8iWX8hFLu
|
||||
nza3mMKTSjcThnpR/yA1S0ipATsdQ5c5xjceliSLDxImBcBaMtvGejgOlFwC6zTz
|
||||
5CJAnLo8odQtAgaaUtGJU145OAHM/cTA0xKd+nh0UvuJHT56Ur6dZ/VKzONnWsUW
|
||||
qI/YVp7mRvv1PimN74ppTQSadU1s3gyq3b7mnl/aWjN42/G6kO27NXA1lVblnFk/
|
||||
Cee6HFxUIy5upTFXnAm1DaEFVdzQ1dxBAEXwIbh2WOXeVCyDONzaqVcYPYQKG5NT
|
||||
KbYY08rnDmRFlURHFQ/eEr49zniLrQRfL3pSNCEGmuVpPAEsuGQ5EQW1b8aEFMgp
|
||||
IR+Jo59JyU04HrP27VctyUEBT4MCQn4G9gN6Qy1EKTKq49UVNR+1eMtuq9/o6tXl
|
||||
rwepnO9AITclPdpvGc93hTshEBZFQF+rHkUMoj7jXr9zAGchRoY8cxaJM0DGrpjc
|
||||
uGONAgMBAAGjPzA9MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcD
|
||||
AQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAYEAgiC2
|
||||
LYPXPCtuaF7qGbas0A5zYtPr0PrXaILl4uYA63+ZXKPMOQ+LkdgRzSQxvKLrPLQM
|
||||
/LwWOTONuqT2sw8Wj+MilzDOXIlEWG2Gqy3/xS7H5RAkZqjVHhuBRXnJiZEl5HAh
|
||||
ASMGiyejII2uN7k+5sjCFmuSfdcI18f/AjUL5fz53TpIJinyCakQipdicI9jZvLR
|
||||
jJ2sqy9wJ3yhTtUm5M33bsLPjhnwMkTTYvvMomfRI8qUYflWxb5BZ82FvNVUE9kA
|
||||
hDdJzluINMofMAblyf9TxX0q1bunPc9soAMtUSDWRmNtviV9uggEdtGYrmDrK7Dz
|
||||
+89AB60QSN6MJzVNPdJZCPvefuJjk9isQBUbQE/CsVFeooKJ/DU5arbUV2mjaifV
|
||||
Z6GxHiEkynSWaNMQLioi+vPguMdAuotdqpInVjCLKJbKiOXrYfIhYJFATc0lRBHx
|
||||
9LUH020HOACgX+WVFiDEDx7OCu868IbDJK/gryb5IfIpbaY4xit9eoqMS4BP
|
||||
-----END CERTIFICATE-----
|
47
test/h4/config.xml
Normal file
47
test/h4/config.xml
Normal file
@ -0,0 +1,47 @@
|
||||
<configuration version="10">
|
||||
<folder id="default" path="s4" ro="false" rescanIntervalS="60" ignorePerms="false" autoNormalize="false">
|
||||
<device id="7PBCTLL-JJRYBSA-MOWZRKL-MSDMN4N-4US4OMX-SYEXUS4-HSBGNRY-CZXRXAT"></device>
|
||||
<versioning></versioning>
|
||||
<copiers>1</copiers>
|
||||
<pullers>16</pullers>
|
||||
<hashers>0</hashers>
|
||||
<order>random</order>
|
||||
<ignoreDelete>false</ignoreDelete>
|
||||
</folder>
|
||||
<device id="7PBCTLL-JJRYBSA-MOWZRKL-MSDMN4N-4US4OMX-SYEXUS4-HSBGNRY-CZXRXAT" name="s4" compression="metadata" introducer="false">
|
||||
<address>dynamic</address>
|
||||
</device>
|
||||
<gui enabled="true" tls="false">
|
||||
<address>127.0.0.1:8084</address>
|
||||
<apikey>PMA5yUTG-Mw98nJ0YEtWTCHlM5O4aNi0</apikey>
|
||||
</gui>
|
||||
<options>
|
||||
<listenAddress>127.0.0.1:22004</listenAddress>
|
||||
<globalAnnounceServer>udp4://announce.syncthing.net:22026</globalAnnounceServer>
|
||||
<globalAnnounceServer>udp6://announce-v6.syncthing.net:22026</globalAnnounceServer>
|
||||
<globalAnnounceEnabled>false</globalAnnounceEnabled>
|
||||
<localAnnounceEnabled>false</localAnnounceEnabled>
|
||||
<localAnnouncePort>21025</localAnnouncePort>
|
||||
<localAnnounceMCAddr>[ff32::5222]:21026</localAnnounceMCAddr>
|
||||
<maxSendKbps>0</maxSendKbps>
|
||||
<maxRecvKbps>0</maxRecvKbps>
|
||||
<reconnectionIntervalS>60</reconnectionIntervalS>
|
||||
<startBrowser>false</startBrowser>
|
||||
<upnpEnabled>false</upnpEnabled>
|
||||
<upnpLeaseMinutes>60</upnpLeaseMinutes>
|
||||
<upnpRenewalMinutes>30</upnpRenewalMinutes>
|
||||
<upnpTimeoutSeconds>10</upnpTimeoutSeconds>
|
||||
<urAccepted>-1</urAccepted>
|
||||
<urUniqueID></urUniqueID>
|
||||
<restartOnWakeup>true</restartOnWakeup>
|
||||
<autoUpgradeIntervalH>12</autoUpgradeIntervalH>
|
||||
<keepTemporariesH>24</keepTemporariesH>
|
||||
<cacheIgnoredFiles>true</cacheIgnoredFiles>
|
||||
<progressUpdateIntervalS>5</progressUpdateIntervalS>
|
||||
<symlinksEnabled>true</symlinksEnabled>
|
||||
<limitBandwidthInLan>false</limitBandwidthInLan>
|
||||
<databaseBlockCacheMiB>0</databaseBlockCacheMiB>
|
||||
<pingTimeoutS>30</pingTimeoutS>
|
||||
<pingIdleTimeS>60</pingIdleTimeS>
|
||||
</options>
|
||||
</configuration>
|
23
test/h4/https-cert.pem
Normal file
23
test/h4/https-cert.pem
Normal file
@ -0,0 +1,23 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID3zCCAkegAwIBAgIIWH6f9/hiHaowDQYJKoZIhvcNAQELBQAwDzENMAsGA1UE
|
||||
AxMEc3lubzAeFw0xNTA3MjIwNzE1MjlaFw00OTEyMzEyMzU5NTlaMA8xDTALBgNV
|
||||
BAMTBHN5bm8wggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCgideynuoI
|
||||
MfN2PR7WfPWvRjnYNuNp5U1C5GzAfrKxVaHkfpt+AsXHHsuo1Xl3gdsIs1Uc2Z8R
|
||||
yLPxFgT+bLKKqwTw4D/9JTHtF2vOLkZLB4/0Bhe2BAXepEEIZDqEHsNE7A8ma9Jv
|
||||
JlBxW55xoXUE5ak2tNvxQneoDj+WKpd24jyZBMp/TC52dhy6TmDfahrQjU29Nz7n
|
||||
tlVC1eol7YqB7+M1CXK2OK74m9J9G8tnweDKJKPv9t011dIhyd2GqRI36fU1EuIC
|
||||
+NSWhcl1VGEa3eCN9Bn+pUo5oDSiMfGmbVo77al31wpN+2+BprH/JTWSWtvBG6uh
|
||||
Cyq5cqkDxMeXmCD863+xorE0hyqZkRrS2XSaJI7hhOgVCUUrfPMK3p9n1pkZ+RfN
|
||||
AtYFPhit2bJyjSBJNN0qxnmMHspZFO+eoeNQkaeL7sDeHLo2ZEUIJMyq4ElsimLU
|
||||
i/+bQCaHl4vz/rz8nRNnIsm4o2adgLie3ZA2lJ+5vEBN+1GlaHIrEnUCAwEAAaM/
|
||||
MD0wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD
|
||||
AjAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBgQBsbVHPEvzX2Emas+yG
|
||||
zbKa1wcuxNWn7nmYjz8YXuFURjGAt1U8wPV+YhgZrhR1rImwGRkXjRwL3vCvm5xi
|
||||
aTNNK2g132amMKhWcAwm/bXJsW3smFpUmmb6j1jZj2eQo3UFNpEql+GzHF/iLWgA
|
||||
74xsqRkqTR/tkoD/W47ASn92rlj8vKmVafiq132/YlqxzaJB4FQyfmdHd1HMsStk
|
||||
r531DXSBsK9CBnM/oEkoCBsJFi6xiUNf7D7wjvoVnCcrIx4bNXiMKgbZA/M0mh9t
|
||||
bDI5b+2j1Af7npPzHAEYEWbWSGwpDBnpB9PuG11WjozLpwDA2My5yjiwHQYw3cIV
|
||||
QM17Oia97QjgOLbbG5Hpy6SF0KxUyCINpg780U7WKyVLherpdQ1ABRmlC0laXDh5
|
||||
Oq500d316ej28VITWj3gMhocw4KwXpkjh9cweLTPV7wiUsoO2ksEMjEPdGCjzHXg
|
||||
k7KQB7dqbOS7VIOJj8+GPbaf3aTdG+b1z3KVcDMH+59TddE=
|
||||
-----END CERTIFICATE-----
|
39
test/h4/https-key.pem
Normal file
39
test/h4/https-key.pem
Normal file
@ -0,0 +1,39 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
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
|
||||
-----END RSA PRIVATE KEY-----
|
39
test/h4/key.pem
Normal file
39
test/h4/key.pem
Normal file
@ -0,0 +1,39 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
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
|
||||
-----END RSA PRIVATE KEY-----
|
85
test/norestart_test.go
Normal file
85
test/norestart_test.go
Normal file
@ -0,0 +1,85 @@
|
||||
// Copyright (C) 2014 The Syncthing Authors.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
// +build integration
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/syncthing/protocol"
|
||||
"github.com/syncthing/syncthing/internal/config"
|
||||
"github.com/syncthing/syncthing/internal/rc"
|
||||
)
|
||||
|
||||
func TestAddDeviceWithoutRestart(t *testing.T) {
|
||||
log.Println("Cleaning...")
|
||||
err := removeAll("s1", "h1/index*", "s4", "h4/index*")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
log.Println("Generating files...")
|
||||
err = generateFiles("s1", 100, 18, "../LICENSE")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
p1 := startInstance(t, 1)
|
||||
defer checkedStop(t, p1)
|
||||
|
||||
p4 := startInstance(t, 4)
|
||||
defer checkedStop(t, p4)
|
||||
|
||||
if ok, err := p1.ConfigInSync(); err != nil || !ok {
|
||||
t.Fatal("p1 should be in sync;", ok, err)
|
||||
}
|
||||
if ok, err := p4.ConfigInSync(); err != nil || !ok {
|
||||
t.Fatal("p4 should be in sync;", ok, err)
|
||||
}
|
||||
|
||||
// Add the p1 device to p4. Back up and restore p4's config first.
|
||||
|
||||
log.Println("Adding p1 to p4...")
|
||||
|
||||
os.Remove("h4/config.xml.orig")
|
||||
os.Rename("h4/config.xml", "h4/config.xml.orig")
|
||||
defer os.Rename("h4/config.xml.orig", "h4/config.xml")
|
||||
|
||||
cfg, err := p4.GetConfig()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
devCfg := config.DeviceConfiguration{
|
||||
DeviceID: p1.ID(),
|
||||
Name: "s1",
|
||||
Addresses: []string{"127.0.0.1:22001"},
|
||||
Compression: protocol.CompressMetadata,
|
||||
}
|
||||
cfg.Devices = append(cfg.Devices, devCfg)
|
||||
|
||||
cfg.Folders[0].Devices = append(cfg.Folders[0].Devices, config.FolderDeviceConfiguration{DeviceID: p1.ID()})
|
||||
|
||||
if err = p4.PostConfig(cfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// The change should not require a restart, so the config should be "in sync"
|
||||
|
||||
if ok, err := p4.ConfigInSync(); err != nil || !ok {
|
||||
t.Fatal("p4 should be in sync;", ok, err)
|
||||
}
|
||||
|
||||
// Wait for the devices to connect and sync.
|
||||
|
||||
log.Println("Waiting for p1 and p4 to connect and sync...")
|
||||
|
||||
rc.AwaitSync("default", p1, p4)
|
||||
}
|
Loading…
Reference in New Issue
Block a user