mirror of
https://github.com/octoleo/syncthing.git
synced 2024-11-19 19:45:12 +00:00
Add devices without restart (fixes #2083)
This commit is contained in:
parent
e205f8afbb
commit
76480adda5
@ -82,8 +82,6 @@ type FolderConfiguration struct {
|
|||||||
IgnoreDelete bool `xml:"ignoreDelete" json:"ignoreDelete"`
|
IgnoreDelete bool `xml:"ignoreDelete" json:"ignoreDelete"`
|
||||||
|
|
||||||
Invalid string `xml:"-" json:"invalid"` // Set at runtime when there is an error, not saved
|
Invalid string `xml:"-" json:"invalid"` // Set at runtime when there is an error, not saved
|
||||||
|
|
||||||
deviceIDs []protocol.DeviceID
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FolderConfiguration) Copy() FolderConfiguration {
|
func (f FolderConfiguration) Copy() FolderConfiguration {
|
||||||
@ -144,12 +142,11 @@ func (f *FolderConfiguration) HasMarker() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *FolderConfiguration) DeviceIDs() []protocol.DeviceID {
|
func (f *FolderConfiguration) DeviceIDs() []protocol.DeviceID {
|
||||||
if f.deviceIDs == nil {
|
deviceIDs := make([]protocol.DeviceID, len(f.Devices))
|
||||||
for _, n := range f.Devices {
|
for i, n := range f.Devices {
|
||||||
f.deviceIDs = append(f.deviceIDs, n.DeviceID)
|
deviceIDs[i] = n.DeviceID
|
||||||
}
|
}
|
||||||
}
|
return deviceIDs
|
||||||
return f.deviceIDs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type VersioningConfiguration struct {
|
type VersioningConfiguration struct {
|
||||||
|
@ -691,14 +691,7 @@ func (m *Model) Close(device protocol.DeviceID, err error) {
|
|||||||
|
|
||||||
conn, ok := m.rawConn[device]
|
conn, ok := m.rawConn[device]
|
||||||
if ok {
|
if ok {
|
||||||
if conn, ok := conn.(*tls.Conn); ok {
|
closeRawConn(conn)
|
||||||
// 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()
|
|
||||||
}
|
}
|
||||||
delete(m.protoConn, device)
|
delete(m.protoConn, device)
|
||||||
delete(m.rawConn, 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 {
|
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.
|
// 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
|
// Go through the folder configs and figure out if we need to restart or not.
|
||||||
if !reflect.DeepEqual(from.Folders, to.Folders) {
|
|
||||||
|
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
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removing a device requres restart
|
// This folder exists on both sides. Compare the device lists, as we
|
||||||
toDevs := make(map[protocol.DeviceID]bool, len(from.Devices))
|
// can handle adding a device (but not currently removing one).
|
||||||
for _, dev := range to.Devices {
|
|
||||||
toDevs[dev.DeviceID] = true
|
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 := mapDeviceCfgs(from.Devices)
|
||||||
for _, dev := range from.Devices {
|
for _, dev := range from.Devices {
|
||||||
if _, ok := toDevs[dev.DeviceID]; !ok {
|
if _, ok := toDevs[dev.DeviceID]; !ok {
|
||||||
|
if debug {
|
||||||
|
l.Debugln(m, "requires restart, device", dev.DeviceID, "was removed")
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// All of the generic options require restart
|
// All of the generic options require restart
|
||||||
if !reflect.DeepEqual(from.Options, to.Options) {
|
if !reflect.DeepEqual(from.Options, to.Options) {
|
||||||
|
if debug {
|
||||||
|
l.Debugln(m, "requires restart, options differ")
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
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 {
|
func filterIndex(folder string, fs []protocol.FileInfo, dropDeletes bool) []protocol.FileInfo {
|
||||||
for i := 0; i < len(fs); {
|
for i := 0; i < len(fs); {
|
||||||
if fs[i].Flags&^protocol.FlagsAll != 0 {
|
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
|
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
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Process) ID() protocol.DeviceID {
|
||||||
|
return p.id
|
||||||
|
}
|
||||||
|
|
||||||
// LogTo creates the specified log file and ensures that stdout and stderr
|
// LogTo creates the specified log file and ensures that stdout and stderr
|
||||||
// from the Start()ed process is redirected there. Must be called before
|
// from the Start()ed process is redirected there. Must be called before
|
||||||
// Start().
|
// Start().
|
||||||
@ -229,6 +233,34 @@ func (p *Process) RescanDelay(folder string, delaySeconds int) error {
|
|||||||
return err
|
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 {
|
func InSync(folder string, ps ...*Process) bool {
|
||||||
for _, p := range ps {
|
for _, p := range ps {
|
||||||
p.eventMut.Lock()
|
p.eventMut.Lock()
|
||||||
|
2
test/.gitignore
vendored
2
test/.gitignore
vendored
@ -1,6 +1,7 @@
|
|||||||
s1
|
s1
|
||||||
s2
|
s2
|
||||||
s3
|
s3
|
||||||
|
s4
|
||||||
s12-1
|
s12-1
|
||||||
s12-2
|
s12-2
|
||||||
s23-2
|
s23-2
|
||||||
@ -20,3 +21,4 @@ h*/index*
|
|||||||
panic-*.log
|
panic-*.log
|
||||||
audit-*.log
|
audit-*.log
|
||||||
h*/config.xml.v*
|
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="I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU"></device>
|
||||||
<device id="JMFJCXB-GZDE4BN-OCJE3VF-65GYZNU-AIVJRET-3J6HMRQ-AUQIGJO-FKNHMQU"></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="373HSRP-QLPNLIE-JYKZVQF-P4PKZ63-R2ZE6K3-YD442U2-JHBGBQG-WWXAHAU"></device>
|
||||||
|
<device id="7PBCTLL-JJRYBSA-MOWZRKL-MSDMN4N-4US4OMX-SYEXUS4-HSBGNRY-CZXRXAT"></device>
|
||||||
<versioning></versioning>
|
<versioning></versioning>
|
||||||
<lenientMtimes>false</lenientMtimes>
|
<lenientMtimes>false</lenientMtimes>
|
||||||
<copiers>1</copiers>
|
<copiers>1</copiers>
|
||||||
@ -31,6 +32,9 @@
|
|||||||
<device id="373HSRP-QLPNLIE-JYKZVQF-P4PKZ63-R2ZE6K3-YD442U2-JHBGBQG-WWXAHAU" name="s3" compression="metadata" introducer="false">
|
<device id="373HSRP-QLPNLIE-JYKZVQF-P4PKZ63-R2ZE6K3-YD442U2-JHBGBQG-WWXAHAU" name="s3" compression="metadata" introducer="false">
|
||||||
<address>127.0.0.1:22003</address>
|
<address>127.0.0.1:22003</address>
|
||||||
</device>
|
</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">
|
<gui enabled="true" tls="false">
|
||||||
<address>127.0.0.1:8081</address>
|
<address>127.0.0.1:8081</address>
|
||||||
<user>testuser</user>
|
<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-----
|
||||||
|
MIIG4wIBAAKCAYEA4nE2FPVQkfMStJms0SUEjSi5qUC4I2+aCFD+q6rLJHhgzdvj
|
||||||
|
XoQ8iWX8hFLunza3mMKTSjcThnpR/yA1S0ipATsdQ5c5xjceliSLDxImBcBaMtvG
|
||||||
|
ejgOlFwC6zTz5CJAnLo8odQtAgaaUtGJU145OAHM/cTA0xKd+nh0UvuJHT56Ur6d
|
||||||
|
Z/VKzONnWsUWqI/YVp7mRvv1PimN74ppTQSadU1s3gyq3b7mnl/aWjN42/G6kO27
|
||||||
|
NXA1lVblnFk/Cee6HFxUIy5upTFXnAm1DaEFVdzQ1dxBAEXwIbh2WOXeVCyDONza
|
||||||
|
qVcYPYQKG5NTKbYY08rnDmRFlURHFQ/eEr49zniLrQRfL3pSNCEGmuVpPAEsuGQ5
|
||||||
|
EQW1b8aEFMgpIR+Jo59JyU04HrP27VctyUEBT4MCQn4G9gN6Qy1EKTKq49UVNR+1
|
||||||
|
eMtuq9/o6tXlrwepnO9AITclPdpvGc93hTshEBZFQF+rHkUMoj7jXr9zAGchRoY8
|
||||||
|
cxaJM0DGrpjcuGONAgMBAAECggGAf0LhAiZcgan6eUVkuqXzSOH6dgTJeCDgkIv0
|
||||||
|
lMYIJRcCUK+juRrYat/GaxewxAocZN31qWAKuSlFq/yN9yF+2hI/AB2deqi/p+Ih
|
||||||
|
xPaOJ+1SxAKAKXAXwYl0mnvIFg6qAWspaEm2gcz0LldUtmXeAnwAmR5awEVWQ84u
|
||||||
|
kfSLusPCO36lOCfDQiMLkxfxBArTqtri0EIKMkVoX5eKVp6fsA0zghfcb4M6WQfF
|
||||||
|
z6vd4L6Z+5mf/QhzFNshcB04MHjqMNRY5WQATZiT1KW3z1kzUWe5eWWSxYQHOVEu
|
||||||
|
VOZuMpsq2TuwBEJDEzzJoOVXRzx6AfSNdyrGYEkq05h/vxwQZTIdZKs97s1nwzu2
|
||||||
|
pkltY1Pf3BdjAvfpCAkxmdu8l+fjlMmgav/lT2O4ZHTbu1MaqNLN5QLGiLxS0I6f
|
||||||
|
gdS9iNgYMVwfpGi7UVNLqrG2nxQmYB0LQyZqNFa+9wNbUzN3h3Qq6eKTXl0uBP5C
|
||||||
|
PdMUdJ3pF7iJM8tshcTb9ALBU/wBAoHBAOVpjYyXtNQOBm/aFkTcJB81AeBgCk3f
|
||||||
|
lxWAs+GwprlPnwCZdH5CvYD2ULGChwaGoYXItRFbWUyP6Tl9c7g3c/MRZJ1M78P9
|
||||||
|
VXA30KPKm9T2dT5ZDCJSUnkZPYP0EagfpYJ9dRxK/55uZ+IGtbXcjkPAVe3wzZfZ
|
||||||
|
8aWgg9w/qmqgiJ8PUmsYY6lILokj2uanmYo410e3RPvN1+qei78RBW6XAh8yJJNL
|
||||||
|
R7vjpjcxtWvY/PKt8b2Yo+DpnHYWm/AqyQKBwQD8r4npkjzrbrS5BQ1mkNDnSaax
|
||||||
|
p7j0hWW+bN0c/EHial2ESKw6vnN/Y+6WcdMq1SgiwkFA7OpthHhY/bUkuyu2BQyo
|
||||||
|
dLFL05KOusS98YTOdMlho4lGJS4HdCi9qeYuroS8gjYsOmDf2PdM1bHKjzkGG0JL
|
||||||
|
igewb6AaF6Yp46jbzqz+PE6WbTTdkfdWXtmDIRTTTOfY7ovG0xLAaYJqNEOzbnQT
|
||||||
|
Emj0ggYNaokGfO6uOk6okuRP7VLaVnxXbvoeUKUCgcBIbORlKFfMQolBsqYpIx68
|
||||||
|
Q23OOkPGhfoarcEcVTqtcjeOZuPiIIvXNOwQvlaGduZzaAPR8PbmNuC4Z6Sq2cbf
|
||||||
|
S/RpvKpNQ6M/hD94FjTQLOaiwlYUV8z1skQ7bkhMvYDxC053mi3NBKoDL38aZQD8
|
||||||
|
3rHCJq2hbQre8Sfv1qGke/3lyV6JtO9xt/oJDarD+tF8U6mTWIaMwFWUGm2f6m2+
|
||||||
|
linzU088uR1ycdI9xpGx9JUWwFd7Nb82+EmO9mBQmBECgcEAqHubJ2RcvlZ4pg1a
|
||||||
|
XBMfV7hiL3638kKoDoqj/FmuzHtDk5qpTBoFBOHrCeEnfh3WvyZrQBE4VoHHhP7V
|
||||||
|
s4IhqSJAyGnWdcrCo+yglk3d0ZNJW5MhSuYrhMjNCXmpg2LWGqNv35mlUlxmuJKc
|
||||||
|
E4Xf7dRrJdcJPXmQdRVjs/aadsWdz38Cn4Z9g2d6Vdq0iZybODDFPn4AMTg3/pfb
|
||||||
|
X1kt8wwo1TanSLERvAxXBT50HzO9kuUu2qRRZEfabKoQl/oJAoHAehR8ULlvRKFi
|
||||||
|
ZAW/uzKT3CLEa0z8JDdQTEsfxAfaeJ/EjMHgxdni5b45c80MBJbmJyetiMg5tJxM
|
||||||
|
wGKmmux/PuDjg5YEdvJLjIZvBrGlZvLlSw9US13zn+RKglKveGBOxc4qx56AJn1Z
|
||||||
|
GLcpjdNq4kmbXq5DtSig+jpqnfAU9bKF9duOSxKoYQv9NapndI900ozW98+1SWiC
|
||||||
|
bxvuPS5n7boLfwLlmvIhX7L/V7iLc5rCAI+0b08JsmMmIDOlytJW
|
||||||
|
-----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