Skip to content

Commit fc9e266

Browse files
Delete backend-notification queues from federation-v0 and federation-v1 after running tests (#4374)
This ensures that the queues don't accumulate in the statically deployed instances over time. https://wearezeta.atlassian.net/browse/WPB-11810 Co-authored-by: Akshay Mankar <[email protected]>
1 parent 6092fbc commit fc9e266

File tree

15 files changed

+173
-30
lines changed

15 files changed

+173
-30
lines changed

.envrc

+9-4
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,16 @@ export NIX_CONFIG='extra-experimental-features = nix-command'
1717

1818
[[ -d "$layout_dir" ]] || mkdir -p "$layout_dir"
1919

20-
if [[ ! -d "$env_dir" || ! -f "$layout_dir/nix-rebuild" || "$store_paths" != $(< "$layout_dir/nix-rebuild" ) ]]; then
20+
if [[ ! -d "$env_dir" || ! -f "$layout_dir/nix-rebuild" || "$store_paths" != $(<"$layout_dir/nix-rebuild") ]]; then
2121
bcmd=nix
22-
if command -v nom &> /dev/null; then
22+
if command -v nom &>/dev/null; then
2323
if [[ "${USE_NOM}" != "0" ]]; then
2424
bcmd=nom
2525
fi
2626
fi
2727
echo "🔧 Building environment"
2828
$bcmd build -f nix wireServer.devEnv -Lv --out-link ./.env
29-
echo "$store_paths" > "$layout_dir/nix-rebuild"
29+
echo "$store_paths" >"$layout_dir/nix-rebuild"
3030
fi
3131

3232
PATH_add "./.env/bin"
@@ -49,8 +49,13 @@ export LANG=en_US.UTF-8
4949
export RABBITMQ_USERNAME=guest
5050
export RABBITMQ_PASSWORD=alpaca-grapefruit
5151

52-
# Redis
52+
export RABBITMQ_USERNAME_V0=guest
53+
export RABBITMQ_PASSWORD_V0=alpaca-grapefruit
54+
55+
export RABBITMQ_USERNAME_V1=guest
56+
export RABBITMQ_PASSWORD_V1=alpaca-grapefruit
5357

58+
# Redis
5459
export REDIS_PASSWORD=very-secure-redis-cluster-password
5560
export REDIS_ADDITIONAL_WRITE_PASSWORD=very-secure-redis-master-password
5661

changelog.d/5-internal/WPB-11810

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Delete federation V0 and V1 queues after integration tests

charts/integration/templates/configmap.yaml

+14
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,20 @@ data:
7070
rabbitmq:
7171
host: rabbitmq
7272
adminPort: 15671
73+
tls: true
74+
vHost: /
75+
76+
rabbitmq-v0:
77+
host: rabbitmq.wire-federation-v0.svc.cluster.local
78+
adminPort: 15672
79+
tls: false
80+
vHost: /
81+
82+
rabbitmq-v1:
83+
host: rabbitmq.wire-federation-v1.svc.cluster.local
84+
adminPort: 15672
85+
tls: false
86+
vHost: /
7387
7488
backendTwo:
7589

charts/integration/templates/integration-integration.yaml

+14
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,20 @@ spec:
310310
secretKeyRef:
311311
name: brig
312312
key: rabbitmqPassword
313+
- name: RABBITMQ_USERNAME_V0
314+
value: "wire-server"
315+
- name: RABBITMQ_PASSWORD_V0
316+
valueFrom:
317+
secretKeyRef:
318+
name: rabbitmq-v0
319+
key: rabbitmq-password
320+
- name: RABBITMQ_USERNAME_V1
321+
value: "wire-server"
322+
- name: RABBITMQ_PASSWORD_V1
323+
valueFrom:
324+
secretKeyRef:
325+
name: rabbitmq-v1
326+
key: rabbitmq-password
313327
{{- if hasKey .Values.secrets "redisUsername" }}
314328
- name: REDIS_USERNAME
315329
valueFrom:

hack/bin/integration-test.sh

+6
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ summary() {
5050
done
5151
}
5252

53+
# Copy the secrets from the wire-federation-v0 namespace to the current namespace to be able to delete RabbitMQ queues that are created by the integration tests to avoid overflows
54+
kubectl -n "$NAMESPACE" delete --force secret rabbitmq-v0 || true
55+
kubectl -n wire-federation-v0 get secrets rabbitmq -ojson | jq 'del(.metadata.namespace) | del(.metadata.resourceVersion) | del(.metadata.uid) | .metadata.name="rabbitmq-v0"' | kubectl -n "$NAMESPACE" apply -f -
56+
kubectl -n "$NAMESPACE" delete --force secret rabbitmq-v1 || true
57+
kubectl -n wire-federation-v1 get secrets rabbitmq -ojson | jq 'del(.metadata.namespace) | del(.metadata.resourceVersion) | del(.metadata.uid) | .metadata.name="rabbitmq-v1"' | kubectl -n "$NAMESPACE" apply -f -
58+
5359
# Run tests in parallel using GNU parallel (see https://www.gnu.org/software/parallel/)
5460
# The below commands are a little convoluted, but we wish to:
5561
# - run integration tests. If they fail, keep track of this, but still go and get logs, so we see what failed

integration/test/Test/Events.hs

+4-1
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,10 @@ killConnection backend = do
570570
port = 0,
571571
adminPort = fromIntegral rc.adminPort,
572572
vHost = Text.pack backend.berVHost,
573-
tls = Just $ RabbitMqTlsOpts Nothing True
573+
tls =
574+
if rc.tls
575+
then Just $ RabbitMqTlsOpts Nothing True
576+
else Nothing
574577
}
575578
servantClient <- liftIO $ mkRabbitMqAdminClientEnv opts
576579
name <- do

integration/test/Testlib/Env.hs

+2
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ mkGlobalEnv cfgFile = do
109109
gServicesCwdBase = devEnvProjectRoot <&> (</> "services"),
110110
gBackendResourcePool = resourcePool,
111111
gRabbitMQConfig = intConfig.rabbitmq,
112+
gRabbitMQConfigV0 = intConfig.rabbitmqV0,
113+
gRabbitMQConfigV1 = intConfig.rabbitmqV1,
112114
gTempDir = tempDir,
113115
gTimeOutSeconds = timeOutSeconds
114116
}

integration/test/Testlib/ResourcePool.hs

+4-5
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import Data.Functor
2121
import Data.IORef
2222
import qualified Data.Set as Set
2323
import Data.String
24-
import qualified Data.Text as T
2524
import Data.Tuple
2625
import Database.CQL.IO
2726
import GHC.Stack (HasCallStack)
@@ -86,13 +85,13 @@ deleteAllRabbitMQQueues rc resource = do
8685
{ host = rc.host,
8786
port = 0,
8887
adminPort = fromIntegral rc.adminPort,
89-
vHost = T.pack resource.berVHost,
88+
vHost = fromString resource.berVHost,
9089
tls = Just $ RabbitMqTlsOpts Nothing True
9190
}
9291
client <- mkRabbitMqAdminClientEnv opts
93-
queues <- listQueuesByVHost client (T.pack resource.berVHost) Nothing Nothing
94-
for_ queues $ \queue ->
95-
deleteQueue client (T.pack resource.berVHost) queue.name
92+
queuesPage <- listQueuesByVHost client (fromString resource.berVHost) (fromString "") False 100 1
93+
for_ queuesPage.items $ \queue ->
94+
deleteQueue client (fromString resource.berVHost) queue.name
9695

9796
deleteAllDynamicBackendConfigs :: BackendResource -> Client ()
9897
deleteAllDynamicBackendConfigs resource = write cql (defQueryParams LocalQuorum ())

integration/test/Testlib/Run.hs

+46
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,13 @@ import Data.Foldable
99
import Data.Function
1010
import Data.Functor
1111
import Data.List
12+
import Data.Maybe (fromMaybe)
13+
import Data.String (IsString (fromString))
14+
import Data.Text (Text)
15+
import qualified Data.Text as T
1216
import Data.Time.Clock
17+
import Network.AMQP.Extended
18+
import Network.RabbitMqAdmin
1319
import RunAllTests
1420
import System.Directory
1521
import System.Environment
@@ -133,11 +139,51 @@ runTests tests mXMLOutput cfg = do
133139
pure (TestSuiteReport [TestCaseReport qname TestSuccess tm])
134140
writeChan output Nothing
135141
wait displayThread
142+
deleteFederationV0AndV1Queues genv
136143
printReport report
137144
mapM_ (saveXMLReport report) mXMLOutput
138145
when (any (\testCase -> testCase.result /= TestSuccess) report.cases) $
139146
exitFailure
140147

148+
deleteFederationV0AndV1Queues :: GlobalEnv -> IO ()
149+
deleteFederationV0AndV1Queues env = do
150+
let testDomains = env.gDomain1 : env.gDomain2 : env.gDynamicDomains
151+
putStrLn "Attempting to delete federation V0 queues..."
152+
(mV0User, mV0Pass) <- readCredsFromEnvWithSuffix "V0"
153+
fromMaybe (putStrLn "No or incomplete credentials for fed V0 RabbitMQ") $
154+
deleteFederationQueues testDomains env.gRabbitMQConfigV0 <$> mV0User <*> mV0Pass
155+
156+
putStrLn "Attempting to delete federation V1 queues..."
157+
(mV1User, mV1Pass) <- readCredsFromEnvWithSuffix "V1"
158+
fromMaybe (putStrLn "No or incomplete credentials for fed V1 RabbitMQ") $
159+
deleteFederationQueues testDomains env.gRabbitMQConfigV1 <$> mV1User <*> mV1Pass
160+
where
161+
readCredsFromEnvWithSuffix :: String -> IO (Maybe Text, Maybe Text)
162+
readCredsFromEnvWithSuffix suffix =
163+
(,)
164+
<$> (fmap fromString <$> lookupEnv ("RABBITMQ_USERNAME_" <> suffix))
165+
<*> (fmap fromString <$> lookupEnv ("RABBITMQ_PASSWORD_" <> suffix))
166+
167+
deleteFederationQueues :: [String] -> RabbitMQConfig -> Text -> Text -> IO ()
168+
deleteFederationQueues testDomains rc username password = do
169+
let opts =
170+
RabbitMqAdminOpts
171+
{ host = rc.host,
172+
port = 0,
173+
adminPort = fromIntegral rc.adminPort,
174+
vHost = fromString rc.vHost,
175+
tls =
176+
if rc.tls
177+
then Just (RabbitMqTlsOpts Nothing True)
178+
else Nothing
179+
}
180+
client <- mkRabbitMqAdminClientEnvWithCreds opts username password
181+
for_ testDomains $ \domain -> do
182+
page <- client.listQueuesByVHost (fromString rc.vHost) (fromString $ "^backend-notifications\\." <> domain <> "$") True 100 1
183+
for_ page.items $ \queue -> do
184+
putStrLn $ "Deleting queue " <> T.unpack queue.name
185+
void $ deleteQueue client (fromString rc.vHost) queue.name
186+
141187
doListTests :: [(String, String, String, x)] -> IO ()
142188
doListTests tests = for_ tests $ \(qname, _desc, _full, _) -> do
143189
putStrLn qname

integration/test/Testlib/Types.hs

+11-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,9 @@ instance FromJSON DynamicBackendConfig
9090

9191
data RabbitMQConfig = RabbitMQConfig
9292
{ host :: String,
93-
adminPort :: Word16
93+
adminPort :: Word16,
94+
tls :: Bool,
95+
vHost :: String
9496
}
9597
deriving (Show)
9698

@@ -100,6 +102,8 @@ instance FromJSON RabbitMQConfig where
100102
RabbitMQConfig
101103
<$> ob .: fromString "host"
102104
<*> ob .: fromString "adminPort"
105+
<*> ob .: fromString "tls"
106+
<*> ob .: fromString "vHost"
103107

104108
-- | Initialised once per testsuite.
105109
data GlobalEnv = GlobalEnv
@@ -115,6 +119,8 @@ data GlobalEnv = GlobalEnv
115119
gServicesCwdBase :: Maybe FilePath,
116120
gBackendResourcePool :: ResourcePool BackendResource,
117121
gRabbitMQConfig :: RabbitMQConfig,
122+
gRabbitMQConfigV0 :: RabbitMQConfig,
123+
gRabbitMQConfigV1 :: RabbitMQConfig,
118124
gTempDir :: FilePath,
119125
gTimeOutSeconds :: Int
120126
}
@@ -127,6 +133,8 @@ data IntegrationConfig = IntegrationConfig
127133
integrationTestHostName :: String,
128134
dynamicBackends :: Map String DynamicBackendConfig,
129135
rabbitmq :: RabbitMQConfig,
136+
rabbitmqV0 :: RabbitMQConfig,
137+
rabbitmqV1 :: RabbitMQConfig,
130138
cassandra :: CassandraConfig
131139
}
132140
deriving (Show, Generic)
@@ -142,6 +150,8 @@ instance FromJSON IntegrationConfig where
142150
<*> o .: fromString "integrationTestHostName"
143151
<*> o .: fromString "dynamicBackends"
144152
<*> o .: fromString "rabbitmq"
153+
<*> o .: fromString "rabbitmq-v0"
154+
<*> o .: fromString "rabbitmq-v1"
145155
<*> o .: fromString "cassandra"
146156

147157
data ServiceMap = ServiceMap

libs/extended/src/Network/AMQP/Extended.hs

+6-3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ module Network.AMQP.Extended
77
withConnection,
88
openConnectionWithRetries,
99
mkRabbitMqAdminClientEnv,
10+
mkRabbitMqAdminClientEnvWithCreds,
1011
mkRabbitMqChannelMVar,
1112
demoteOpts,
1213
RabbitMqTlsOpts (..),
@@ -91,9 +92,8 @@ instance FromJSON RabbitMqAdminOpts where
9192
<*> parseTlsJson v
9293
<*> v .: "adminPort"
9394

94-
mkRabbitMqAdminClientEnv :: RabbitMqAdminOpts -> IO (AdminAPI (AsClientT IO))
95-
mkRabbitMqAdminClientEnv opts = do
96-
(username, password) <- readCredsFromEnv
95+
mkRabbitMqAdminClientEnvWithCreds :: RabbitMqAdminOpts -> Text -> Text -> IO (AdminAPI (AsClientT IO))
96+
mkRabbitMqAdminClientEnvWithCreds opts username password = do
9797
mTlsSettings <- traverse (mkTLSSettings opts.host) opts.tls
9898
let (protocol, managerSettings) = case mTlsSettings of
9999
Nothing -> (Servant.Http, HTTP.defaultManagerSettings)
@@ -107,6 +107,9 @@ mkRabbitMqAdminClientEnv opts = do
107107
(either throwM pure <=< flip runClientM clientEnv)
108108
(toServant $ adminClient basicAuthData)
109109

110+
mkRabbitMqAdminClientEnv :: RabbitMqAdminOpts -> IO (AdminAPI (AsClientT IO))
111+
mkRabbitMqAdminClientEnv opts = readCredsFromEnv >>= uncurry (mkRabbitMqAdminClientEnvWithCreds opts)
112+
110113
-- | When admin opts are needed use `AmqpEndpoint Identity`, otherwise use
111114
-- `AmqpEndpoint NoAdmin`.
112115
data AmqpEndpoint = AmqpEndpoint

libs/extended/src/Network/RabbitMqAdmin.hs

+23-7
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,36 @@ type VHost = Text
1313

1414
type QueueName = Text
1515

16+
data Page a = Page {items :: [a], page :: Int, pageCount :: Int}
17+
deriving (Show, Eq, Generic)
18+
19+
instance (FromJSON a) => FromJSON (Page a) where
20+
parseJSON =
21+
genericParseJSON $
22+
defaultOptions
23+
{ fieldLabelModifier = camelTo2 '_'
24+
}
25+
26+
instance (ToJSON a) => ToJSON (Page a) where
27+
toJSON =
28+
genericToJSON $
29+
defaultOptions
30+
{ fieldLabelModifier = camelTo2 '_'
31+
}
32+
1633
-- | Upstream Docs:
1734
-- https://rawcdn.githack.com/rabbitmq/rabbitmq-server/v3.12.0/deps/rabbitmq_management/priv/www/api/index.html
1835
data AdminAPI route = AdminAPI
19-
{ -- | NOTE: This endpoint can be made paginated, but that complicates
20-
-- consumer code a little. This might be needed for performance tuning
21-
-- later, but perhaps not.
22-
listQueuesByVHost ::
36+
{ listQueuesByVHost ::
2337
route
2438
:- "api"
2539
:> "queues"
2640
:> Capture "vhost" VHost
27-
:> QueryParam "name" Text
28-
:> QueryParam "use_regex" Bool
29-
:> Get '[JSON] [Queue],
41+
:> QueryParam' '[Required, Strict] "name" Text
42+
:> QueryParam' '[Required, Strict] "use_regex" Bool
43+
:> QueryParam' '[Required, Strict] "page_size" Int
44+
:> QueryParam' '[Required, Strict] "page" Int
45+
:> Get '[JSON] (Page Queue),
3046
deleteQueue ::
3147
route
3248
:- "api"

services/background-worker/src/Wire/BackendNotificationPusher.hs

+10-6
Original file line numberDiff line numberDiff line change
@@ -277,14 +277,18 @@ getRemoteDomains adminClient = do
277277
handlers =
278278
skipAsyncExceptions
279279
<> [logRetries (const $ pure True) logErrr]
280-
recovering policy handlers $ const go
280+
recovering policy handlers $ const $ go [] 1
281281
where
282-
go :: AppT IO [Domain]
283-
go = do
282+
go :: [Domain] -> Int -> AppT IO [Domain]
283+
go domains pageNumber = do
284284
vhost <- asks rabbitmqVHost
285-
queues <- liftIO $ listQueuesByVHost adminClient vhost (Just "backend-notifications\\..*") (Just True)
286-
let notifQueuesSuffixes = mapMaybe (\q -> Text.stripPrefix "backend-notifications." q.name) queues
287-
catMaybes <$> traverse (\d -> either (\e -> logInvalidDomain d e >> pure Nothing) (pure . Just) $ mkDomain d) notifQueuesSuffixes
285+
queuesPage <- liftIO $ listQueuesByVHost adminClient vhost "^backend-notifications\\..*" True 100 pageNumber
286+
let notifQueuesSuffixes = mapMaybe (\q -> Text.stripPrefix "backend-notifications." q.name) queuesPage.items
287+
newDomains <- catMaybes <$> traverse (\d -> either (\e -> logInvalidDomain d e >> pure Nothing) (pure . Just) $ mkDomain d) notifQueuesSuffixes
288+
let domainsSoFar = newDomains <> domains
289+
if queuesPage.page >= queuesPage.pageCount
290+
then pure domainsSoFar
291+
else go domainsSoFar (pageNumber + 1)
288292
logInvalidDomain d e =
289293
Log.warn $
290294
Log.msg (Log.val "Found invalid domain in a backend notifications queue name")

services/background-worker/test/Test/Wire/BackendNotificationPusherSpec.hs

+9-3
Original file line numberDiff line numberDiff line change
@@ -353,12 +353,18 @@ mockApi mockAdmin =
353353
deleteConnection = mockDeleteConnection mockAdmin
354354
}
355355

356-
mockListQueuesByVHost :: MockRabbitMqAdmin -> Text -> Maybe Text -> Maybe Bool -> Servant.Handler [Queue]
357-
mockListQueuesByVHost MockRabbitMqAdmin {..} vhost _ _ = do
356+
mockListQueuesByVHost :: MockRabbitMqAdmin -> Text -> Text -> Bool -> Int -> Int -> Servant.Handler (Page Queue)
357+
mockListQueuesByVHost MockRabbitMqAdmin {..} vhost _ _ _ _ = do
358358
atomically $ modifyTVar listQueuesVHostCalls (<> [vhost])
359359
readTVarIO broken >>= \case
360360
True -> throwError $ Servant.err500
361-
False -> pure $ map (\n -> Queue n vhost) queues
361+
False ->
362+
pure
363+
Page
364+
{ items = map (\n -> Queue n vhost) queues,
365+
pageCount = 1,
366+
page = 1
367+
}
362368

363369
mockListDeleteQueue :: MockRabbitMqAdmin -> Text -> Text -> Servant.Handler NoContent
364370
mockListDeleteQueue _ _ _ = do

services/integration.yaml

+14
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,20 @@ dynamicBackends:
164164
rabbitmq:
165165
host: localhost
166166
adminPort: 15671
167+
tls: true
168+
vHost: /
169+
170+
rabbitmq-v0:
171+
host: localhost
172+
adminPort: 15672
173+
tls: false
174+
vHost: federation-v0
175+
176+
rabbitmq-v1:
177+
host: localhost
178+
adminPort: 15672
179+
tls: false
180+
vHost: federation-v1
167181

168182
cassandra:
169183
host: 127.0.0.1

0 commit comments

Comments
 (0)