diff --git a/deps/rabbitmq_cli/lib/rabbitmq/cli/core/merges_default_virtual_host.ex b/deps/rabbitmq_cli/lib/rabbitmq/cli/core/merges_default_virtual_host.ex new file mode 100644 index 0000000000..94b1b768b6 --- /dev/null +++ b/deps/rabbitmq_cli/lib/rabbitmq/cli/core/merges_default_virtual_host.ex @@ -0,0 +1,15 @@ +## 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 https://mozilla.org/MPL/2.0/. +## +## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. + +# Should be used by commands that require rabbit app to be stopped +# but need no other execution environment validators. +defmodule RabbitMQ.CLI.Core.MergesDefaultVirtualHost do + defmacro __using__(_) do + quote do + def merge_defaults(args, opts), do: {args, Map.merge(%{vhost: "/"}, opts)} + end + end +end diff --git a/deps/rabbitmq_cli/lib/rabbitmq/cli/queues/commands/reclaim_quorum_memory_command.ex b/deps/rabbitmq_cli/lib/rabbitmq/cli/queues/commands/reclaim_quorum_memory_command.ex new file mode 100644 index 0000000000..3452cc8741 --- /dev/null +++ b/deps/rabbitmq_cli/lib/rabbitmq/cli/queues/commands/reclaim_quorum_memory_command.ex @@ -0,0 +1,69 @@ +## 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 https://mozilla.org/MPL/2.0/. +## +## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. + +defmodule RabbitMQ.CLI.Queues.Commands.ReclaimQuorumMemoryCommand do + alias RabbitMQ.CLI.Core.DocGuide + + @behaviour RabbitMQ.CLI.CommandBehaviour + def scopes(), do: [:diagnostics, :queues] + + use RabbitMQ.CLI.Core.MergesDefaultVirtualHost + use RabbitMQ.CLI.Core.AcceptsOnePositionalArgument + use RabbitMQ.CLI.Core.RequiresRabbitAppRunning + + def run([name] = _args, %{node: node_name, vhost: vhost}) do + case :rabbit_misc.rpc_call(node_name, :rabbit_quorum_queue, :reclaim_memory, [vhost, name]) do + {:error, :classic_queue_not_supported} -> + {:error, "This operation is not applicable to classic queues"} + + other -> + other + end + end + + def output({:error, :not_found}, %{vhost: vhost, formatter: "json"}) do + {:error, + %{ + "result" => "error", + "message" => "Target queue was not found in virtual host '#{vhost}'" + }} + end + def output({:error, error}, %{formatter: "json"}) do + {:error, + %{ + "result" => "error", + "message" => "Failed to perform the operation: #{error}" + }} + end + def output({:error, :not_found}, %{vhost: vhost}) do + {:error, "Target queue was not found in virtual host '#{vhost}'"} + end + use RabbitMQ.CLI.DefaultOutput + + def usage() do + "reclaim_quorum_memory [--vhost ] " + end + + def usage_additional do + [ + ["", "Name of the quorum queue"] + ] + end + + def usage_doc_guides() do + [ + DocGuide.quorum_queues(), + DocGuide.memory_use() + ] + end + + def help_section(), do: :operations + + def description(), do: "Flushes quorum queue processes WAL, performs a full sweep GC on all of its local Erlang processes" + + def banner([name], %{}), + do: "Will flush Raft WAL of quorum queue #{name} ..." +end diff --git a/deps/rabbitmq_cli/test/queues/reclaim_quorum_memory_command_test.exs b/deps/rabbitmq_cli/test/queues/reclaim_quorum_memory_command_test.exs new file mode 100644 index 0000000000..bec7bab50d --- /dev/null +++ b/deps/rabbitmq_cli/test/queues/reclaim_quorum_memory_command_test.exs @@ -0,0 +1,45 @@ +## 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 https://mozilla.org/MPL/2.0/. +## +## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. + +defmodule RabbitMQ.CLI.Queues.Commands.ReclaimQuorumMemoryCommandTest do + use ExUnit.Case, async: false + import TestHelper + + @command RabbitMQ.CLI.Queues.Commands.ReclaimQuorumMemoryCommand + + setup_all do + RabbitMQ.CLI.Core.Distribution.start() + + :ok + end + + setup context do + {:ok, opts: %{ + node: get_rabbit_hostname(), + timeout: context[:test_timeout] || 30000 + }} + end + + + test "validate: treats no arguments as a failure" do + assert @command.validate([], %{}) == {:validation_failure, :not_enough_args} + end + + test "validate: accepts a single positional argument" do + assert @command.validate(["quorum-queue-a"], %{}) == :ok + end + + test "validate: when two or more arguments are provided, returns a failure" do + assert @command.validate(["quorum-queue-a", "one-extra-arg"], %{}) == {:validation_failure, :too_many_args} + assert @command.validate(["quorum-queue-a", "extra-arg", "another-extra-arg"], %{}) == {:validation_failure, :too_many_args} + end + + @tag test_timeout: 3000 + test "run: targeting an unreachable node throws a badrpc" do + assert match?({:badrpc, _}, @command.run(["quorum-queue-a"], + %{node: :jake@thedog, vhost: "/", timeout: 200})) + end +end