Skip to content

Commit 3f88513

Browse files
fisxakshaymankar
andauthored
Disable de-federation to avoid running into a scalability issue (#3582)
https://wearezeta.atlassian.net/browse/WPB-4668 Co-authored-by: Akshay Mankar <[email protected]>
1 parent fd258a9 commit 3f88513

File tree

51 files changed

+148
-2079
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+148
-2079
lines changed

changelog.d/1-api-changes/WPB-3611

Lines changed: 0 additions & 5 deletions
This file was deleted.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Remove de-federation (to avoid a scalability issue).

changelog.d/3-bug-fixes/duplicate-member-notifications

Lines changed: 0 additions & 1 deletion
This file was deleted.

changelog.d/6-federation/WPB-3611

Lines changed: 0 additions & 1 deletion
This file was deleted.

docs/src/understand/configure-federation.md

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -457,13 +457,8 @@ the sysadmin:
457457

458458
* [`PUT`](https://staging-nginz-https.zinfra.io/api-internal/swagger-ui/brig/#/brig/put_i_federation_remotes__domain_)
459459

460-
* [`DELETE`](https://staging-nginz-https.zinfra.io/api-internal/swagger-ui/brig/#/brig/delete_i_federation_remotes__domain_)
461-
- **WARNING:** If you delete a connection, all users from that
462-
remote will be removed from local conversations, and all
463-
conversations hosted by that remote will be removed from the local
464-
backend. Connections between local and remote users that are
465-
removed will be archived, and can be re-established should you
466-
decide to add the same backend later.
460+
* **NOTE:** De-federating (`DELETE`) has been removed from the API to
461+
avoid a scalability issue. Watch out for a fix in the changelog!
467462

468463
The `remotes` list looks like this:
469464

integration/default.nix

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
, Cabal
1616
, case-insensitive
1717
, containers
18+
, cql
19+
, cql-io
1820
, cryptonite
1921
, data-default
2022
, directory
@@ -80,6 +82,8 @@ mkDerivation {
8082
bytestring-conversion
8183
case-insensitive
8284
containers
85+
cql
86+
cql-io
8387
cryptonite
8488
data-default
8589
directory

integration/integration.cabal

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,6 @@ library
105105
Test.Brig
106106
Test.Client
107107
Test.Conversation
108-
Test.Defederation
109108
Test.Demo
110109
Test.Federation
111110
Test.Federator
@@ -143,6 +142,8 @@ library
143142
, bytestring-conversion
144143
, case-insensitive
145144
, containers
145+
, cql
146+
, cql-io
146147
, cryptonite
147148
, data-default
148149
, directory

integration/test/API/BrigInternal.hs

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -99,25 +99,6 @@ updateFedConn' owndom dom fedConn = do
9999
conn <- make fedConn
100100
submit "PUT" $ addJSON conn req
101101

102-
deleteFedConn :: (HasCallStack, MakesValue owndom) => owndom -> String -> App Response
103-
deleteFedConn owndom dom = do
104-
bindResponse (deleteFedConn' owndom dom) $ \res -> do
105-
res.status `shouldMatchRange` (200, 299)
106-
pure res
107-
108-
deleteFedConn' :: (HasCallStack, MakesValue owndom) => owndom -> String -> App Response
109-
deleteFedConn' owndom dom = do
110-
req <- rawBaseRequest owndom Brig Unversioned ("/i/federation/remotes/" <> dom)
111-
submit "DELETE" req
112-
113-
deleteAllFedConns :: (HasCallStack, MakesValue dom) => dom -> App ()
114-
deleteAllFedConns dom = do
115-
readFedConns dom >>= \resp ->
116-
resp.json %. "remotes"
117-
& asList
118-
>>= traverse (\v -> v %. "domain" & asString)
119-
>>= mapM_ (deleteFedConn dom)
120-
121102
registerOAuthClient :: (HasCallStack, MakesValue user, MakesValue name, MakesValue url) => user -> name -> url -> App Response
122103
registerOAuthClient user name url = do
123104
req <- baseRequest user Brig Unversioned "i/oauth/clients"

integration/test/API/GalleyInternal.hs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,3 @@ getFederationStatus user domains =
5151
submit
5252
"GET"
5353
$ req & addJSONObject ["domains" .= domainList]
54-
55-
deleteFederationDomain ::
56-
( HasCallStack
57-
) =>
58-
String ->
59-
App Response
60-
deleteFederationDomain domain = do
61-
req <- rawBaseRequest OwnDomain Galley Unversioned $ joinHttpPath ["i", "federation", domain]
62-
submit "DELETE" req

integration/test/SetupHelpers.hs

Lines changed: 5 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
2+
13
module SetupHelpers where
24

35
import API.Brig qualified as Brig
@@ -9,7 +11,6 @@ import Data.Aeson hiding ((.=))
911
import Data.Aeson.Types qualified as Aeson
1012
import Data.Default
1113
import Data.Function
12-
import Data.List qualified as List
1314
import Data.UUID.V1 (nextUUID)
1415
import Data.UUID.V4 (nextRandom)
1516
import GHC.Stack
@@ -75,14 +76,6 @@ getAllConvs u = do
7576
resp.json
7677
result %. "found" & asList
7778

78-
resetFedConns :: (HasCallStack, MakesValue owndom) => owndom -> App ()
79-
resetFedConns owndom = do
80-
bindResponse (Internal.readFedConns owndom) $ \resp -> do
81-
rdoms :: [String] <- do
82-
rawlist <- resp.json %. "remotes" & asList
83-
(asString . (%. "domain")) `mapM` rawlist
84-
Internal.deleteFedConn' owndom `mapM_` rdoms
85-
8679
randomId :: HasCallStack => App String
8780
randomId = liftIO (show <$> nextRandom)
8881

@@ -95,40 +88,15 @@ randomUserId domain = do
9588
uid <- randomId
9689
pure $ object ["id" .= uid, "domain" .= d]
9790

98-
addFullSearchFor :: [String] -> Value -> App Value
99-
addFullSearchFor domains val =
100-
modifyField
101-
"optSettings.setFederationDomainConfigs"
102-
( \configs -> do
103-
cfg <- assertJust "" configs
104-
xs <- cfg & asList
105-
pure (xs <> [object ["domain" .= domain, "search_policy" .= "full_search"] | domain <- domains])
106-
)
107-
val
108-
109-
fullSearchWithAll :: ServiceOverrides
110-
fullSearchWithAll =
111-
def
112-
{ brigCfg = \val -> do
113-
ownDomain <- asString =<< val %. "optSettings.setFederationDomain"
114-
env <- ask
115-
let remoteDomains = List.delete ownDomain $ [env.domain1, env.domain2] <> env.dynamicDomains
116-
addFullSearchFor remoteDomains val
117-
}
118-
119-
withFederatingBackendsAllowDynamic :: HasCallStack => Int -> ((String, String, String) -> App a) -> App a
120-
withFederatingBackendsAllowDynamic n k = do
91+
withFederatingBackendsAllowDynamic :: HasCallStack => ((String, String, String) -> App a) -> App a
92+
withFederatingBackendsAllowDynamic k = do
12193
let setFederationConfig =
12294
setField "optSettings.setFederationStrategy" "allowDynamic"
123-
>=> removeField "optSettings.setFederationDomainConfigs"
12495
>=> setField "optSettings.setFederationDomainConfigsUpdateFreq" (Aeson.Number 1)
12596
startDynamicBackends
12697
[ def {brigCfg = setFederationConfig},
12798
def {brigCfg = setFederationConfig},
12899
def {brigCfg = setFederationConfig}
129100
]
130-
$ \dynDomains -> do
131-
domains@[domainA, domainB, domainC] <- pure dynDomains
132-
sequence_ [Internal.createFedConn x (Internal.FedConn y "full_search") | x <- domains, y <- domains, x /= y]
133-
liftIO $ threadDelay (n * 1000 * 1000) -- wait for federation status to be updated
101+
$ \[domainA, domainB, domainC] ->
134102
k (domainA, domainB, domainC)

integration/test/Test/Brig.hs

Lines changed: 14 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import API.Brig qualified as Public
44
import API.BrigInternal qualified as Internal
55
import API.Common qualified as API
66
import API.GalleyInternal qualified as Internal
7+
import Control.Concurrent (threadDelay)
78
import Data.Aeson qualified as Aeson
89
import Data.Aeson.Types hiding ((.=))
910
import Data.Set qualified as Set
@@ -29,14 +30,7 @@ testSearchContactForExternalUsers = do
2930
testCrudFederationRemotes :: HasCallStack => App ()
3031
testCrudFederationRemotes = do
3132
otherDomain <- asString OtherDomain
32-
let overrides =
33-
def
34-
{ brigCfg =
35-
setField
36-
"optSettings.setFederationDomainConfigs"
37-
[object ["domain" .= otherDomain, "search_policy" .= "full_search"]]
38-
}
39-
withModifiedBackend overrides $ \ownDomain -> do
33+
withModifiedBackend def $ \ownDomain -> do
4034
let parseFedConns :: HasCallStack => Response -> App [Value]
4135
parseFedConns resp =
4236
-- Pick out the list of federation domain configs
@@ -45,74 +39,40 @@ testCrudFederationRemotes = do
4539
-- Enforce that the values are objects and not something else
4640
>>= traverse (fmap Object . asObject)
4741

48-
addOnce :: (MakesValue fedConn, Ord fedConn2, ToJSON fedConn2, MakesValue fedConn2, HasCallStack) => fedConn -> [fedConn2] -> App ()
49-
addOnce fedConn want = do
42+
addTest :: (MakesValue fedConn, Ord fedConn2, ToJSON fedConn2, MakesValue fedConn2, HasCallStack) => fedConn -> [fedConn2] -> App ()
43+
addTest fedConn want = do
5044
bindResponse (Internal.createFedConn ownDomain fedConn) $ \res -> do
5145
addFailureContext ("res = " <> show res) $ res.status `shouldMatchInt` 200
5246
res2 <- parseFedConns =<< Internal.readFedConns ownDomain
5347
sort res2 `shouldMatch` sort want
5448

55-
addFail :: HasCallStack => MakesValue fedConn => fedConn -> App ()
56-
addFail fedConn = do
57-
bindResponse (Internal.createFedConn' ownDomain fedConn) $ \res -> do
58-
addFailureContext ("res = " <> show res) $ res.status `shouldMatchInt` 533
59-
60-
deleteOnce :: (Ord fedConn, ToJSON fedConn, MakesValue fedConn) => String -> [fedConn] -> App ()
61-
deleteOnce domain want = do
62-
bindResponse (Internal.deleteFedConn ownDomain domain) $ \res -> do
63-
addFailureContext ("res = " <> show res) $ res.status `shouldMatchInt` 200
64-
res2 <- parseFedConns =<< Internal.readFedConns ownDomain
65-
sort res2 `shouldMatch` sort want
66-
67-
deleteFail :: HasCallStack => String -> App ()
68-
deleteFail del = do
69-
bindResponse (Internal.deleteFedConn' ownDomain del) $ \res -> do
70-
addFailureContext ("res = " <> show res) $ res.status `shouldMatchInt` 533
71-
72-
updateOnce :: (MakesValue fedConn, Ord fedConn2, ToJSON fedConn2, MakesValue fedConn2, HasCallStack) => String -> fedConn -> [fedConn2] -> App ()
73-
updateOnce domain fedConn want = do
49+
updateTest :: (MakesValue fedConn, Ord fedConn2, ToJSON fedConn2, MakesValue fedConn2, HasCallStack) => String -> fedConn -> [fedConn2] -> App ()
50+
updateTest domain fedConn want = do
7451
bindResponse (Internal.updateFedConn ownDomain domain fedConn) $ \res -> do
7552
addFailureContext ("res = " <> show res) $ res.status `shouldMatchInt` 200
7653
res2 <- parseFedConns =<< Internal.readFedConns ownDomain
7754
sort res2 `shouldMatch` sort want
7855

79-
updateFail :: (MakesValue fedConn, HasCallStack) => String -> fedConn -> App ()
80-
updateFail domain fedConn = do
81-
bindResponse (Internal.updateFedConn' ownDomain domain fedConn) $ \res -> do
82-
addFailureContext ("res = " <> show res) $ res.status `shouldMatchInt` 533
83-
8456
dom1 :: String <- (<> ".example.com") . UUID.toString <$> liftIO UUID.nextRandom
85-
dom2 :: String <- (<> ".example.com") . UUID.toString <$> liftIO UUID.nextRandom
8657

87-
let remote1, remote1', remote1'' :: Internal.FedConn
58+
let remote1, remote1' :: Internal.FedConn
8859
remote1 = Internal.FedConn dom1 "no_search"
8960
remote1' = remote1 {Internal.searchStrategy = "full_search"}
90-
remote1'' = remote1 {Internal.domain = dom2}
9161

9262
cfgRemotesExpect :: Internal.FedConn
9363
cfgRemotesExpect = Internal.FedConn (cs otherDomain) "full_search"
9464

95-
remote1J <- make remote1
96-
remote1J' <- make remote1'
97-
98-
resetFedConns ownDomain
65+
liftIO $ threadDelay 5_000_000
9966
cfgRemotes <- parseFedConns =<< Internal.readFedConns ownDomain
100-
cfgRemotes `shouldMatch` [cfgRemotesExpect]
67+
cfgRemotes `shouldMatch` ([] @Value)
10168
-- entries present in the config file can be idempotently added if identical, but cannot be
102-
-- updated, deleted or updated.
103-
addOnce cfgRemotesExpect [cfgRemotesExpect]
104-
addFail (cfgRemotesExpect {Internal.searchStrategy = "no_search"})
105-
deleteFail (Internal.domain cfgRemotesExpect)
106-
updateFail (Internal.domain cfgRemotesExpect) (cfgRemotesExpect {Internal.searchStrategy = "no_search"})
69+
-- updated.
70+
addTest cfgRemotesExpect [cfgRemotesExpect]
10771
-- create
108-
addOnce remote1 $ (remote1J : cfgRemotes)
109-
addOnce remote1 $ (remote1J : cfgRemotes) -- idempotency
72+
addTest remote1 [cfgRemotesExpect, remote1]
73+
addTest remote1 [cfgRemotesExpect, remote1] -- idempotency
11074
-- update
111-
updateOnce (Internal.domain remote1) remote1' (remote1J' : cfgRemotes)
112-
updateFail (Internal.domain remote1) remote1''
113-
-- delete
114-
deleteOnce (Internal.domain remote1) cfgRemotes
115-
deleteOnce (Internal.domain remote1) cfgRemotes -- idempotency
75+
updateTest (Internal.domain remote1) remote1' [cfgRemotesExpect, remote1']
11676

11777
testCrudOAuthClient :: HasCallStack => App ()
11878
testCrudOAuthClient = do
@@ -185,7 +145,6 @@ testRemoteUserSearch :: HasCallStack => App ()
185145
testRemoteUserSearch = do
186146
let overrides =
187147
setField "optSettings.setFederationStrategy" "allowDynamic"
188-
>=> removeField "optSettings.setFederationDomainConfigs"
189148
>=> setField "optSettings.setFederationDomainConfigsUpdateFreq" (Aeson.Number 1)
190149
startDynamicBackends [def {brigCfg = overrides}, def {brigCfg = overrides}] $ \dynDomains -> do
191150
domains@[d1, d2] <- pure dynDomains

0 commit comments

Comments
 (0)