Skip to content

Commit

Permalink
CLI commands for #12772
Browse files Browse the repository at this point in the history
(cherry picked from commit 6281dcb)
  • Loading branch information
michaelklishin authored and mergify[bot] committed Jan 4, 2025
1 parent 2541e6e commit c4a8b70
Show file tree
Hide file tree
Showing 6 changed files with 278 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
## 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-2025 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved.

defmodule RabbitMQ.CLI.Ctl.Commands.DisableVhostDeletionProtectionCommand do
alias RabbitMQ.CLI.Core.{DocGuide, Helpers}

@behaviour RabbitMQ.CLI.CommandBehaviour

@metadata_key :protected_from_deletion

def switches(), do: []
def aliases(), do: []

def merge_defaults(args, opts) do
{args, opts}
end

use RabbitMQ.CLI.Core.RequiresRabbitAppRunning
use RabbitMQ.CLI.Core.AcceptsOnePositionalArgument

def run([vhost], %{node: node_name}) do
metadata_patch = %{
@metadata_key => false
}
:rabbit_misc.rpc_call(node_name, :rabbit_vhost, :update_metadata, [
vhost,
metadata_patch,
Helpers.cli_acting_user()
])
end

use RabbitMQ.CLI.DefaultOutput

def usage,
do:
"disable_vhost_deletion_protection <vhost>"

def usage_additional() do
[
["<vhost>", "Virtual host name"]
]
end

def usage_doc_guides() do
[
DocGuide.virtual_hosts()
]
end

def help_section(), do: :virtual_hosts

def description(), do: "Removes deletion protection from a virtual host (so that it can be deleted)"

def banner([vhost], _), do: "Removing deletion protection from virtual host \"#{vhost}\" by updating its metadata..."
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
## 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-2025 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved.

defmodule RabbitMQ.CLI.Ctl.Commands.EnableVhostDeletionProtectionCommand do
alias RabbitMQ.CLI.Core.{DocGuide, Helpers}

@behaviour RabbitMQ.CLI.CommandBehaviour

@metadata_key :protected_from_deletion

def switches(), do: []
def aliases(), do: []

def merge_defaults(args, opts) do
{args, opts}
end

use RabbitMQ.CLI.Core.RequiresRabbitAppRunning
use RabbitMQ.CLI.Core.AcceptsOnePositionalArgument

def run([vhost], %{node: node_name}) do
metadata_patch = %{
@metadata_key => true
}
:rabbit_misc.rpc_call(node_name, :rabbit_vhost, :update_metadata, [
vhost,
metadata_patch,
Helpers.cli_acting_user()
])
end

use RabbitMQ.CLI.DefaultOutput

def usage,
do:
"enable_vhost_deletion_protection <vhost>"

def usage_additional() do
[
["<vhost>", "Virtual host name"]
]
end

def usage_doc_guides() do
[
DocGuide.virtual_hosts()
]
end

def help_section(), do: :virtual_hosts

def description(), do: "Protects a virtual host from deletion (until the protection is removed)"

def banner([vhost], _), do: "Protecting virtual host \"#{vhost}\" from removal by updating its metadata..."
end
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ defmodule RabbitMQ.CLI.Ctl.Commands.UpdateVhostMetadataCommand do

@behaviour RabbitMQ.CLI.CommandBehaviour

@metadata_keys [:description, :tags, :default_queue_type]
@metadata_keys [:description, :tags, :default_queue_type, :protected_from_deletion]

def switches(), do: [description: :string, tags: :string, default_queue_type: :string]
def switches(), do: [description: :string, tags: :string, default_queue_type: :string, protected_from_deletion: :boolean]
def aliases(), do: [d: :description]

def merge_defaults(args, opts) do
Expand Down Expand Up @@ -86,7 +86,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.UpdateVhostMetadataCommand do

def usage,
do:
"update_vhost_metadata <vhost> [--description <description>] [--tags \"<tag1>,<tag2>,<...>\"] [--default-queue-type <quorum|classic|stream>]"
"update_vhost_metadata <vhost> [--description=<description>] [--tags=\"<tag1>,<tag2>,<...>\"] [--default-queue-type=<quorum|classic|stream>] [--protected-from-deletion=<true|false>]"

def usage_additional() do
[
Expand All @@ -96,7 +96,8 @@ defmodule RabbitMQ.CLI.Ctl.Commands.UpdateVhostMetadataCommand do
[
"--default-queue-type <quorum|classic|stream>",
"Queue type to use if no type is explicitly provided by the client"
]
],
["--protected-from-deletion", "When set to true, will make it impossible to delete a virtual host until the protection is removed"]
]
end

Expand All @@ -108,7 +109,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.UpdateVhostMetadataCommand do

def help_section(), do: :virtual_hosts

def description(), do: "Updates metadata (tags, description, default queue type) a virtual host"
def description(), do: "Updates metadata (tags, description, default queue type, protection from deletion) a virtual host"

def banner([vhost], _), do: "Updating metadata of vhost \"#{vhost}\" ..."
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
## 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-2025 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved.

defmodule DisableVhostDeletionProtectionCommandTest do
use ExUnit.Case, async: false
import TestHelper

@command RabbitMQ.CLI.Ctl.Commands.DisableVhostDeletionProtectionCommand
@inverse_command RabbitMQ.CLI.Ctl.Commands.EnableVhostDeletionProtectionCommand
@vhost "disable-vhost-deletion-protection"

setup_all do
RabbitMQ.CLI.Core.Distribution.start()
{:ok, opts: %{node: get_rabbit_hostname()}}
end

setup context do
on_exit(context, fn -> delete_vhost(context[:vhost]) end)
:ok
end

test "validate: no arguments fails validation" do
assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
end

test "validate: too many arguments fails validation" do
assert @command.validate(["test", "extra"], %{}) == {:validation_failure, :too_many_args}
end

test "validate: virtual host name without options fails validation" do
assert @command.validate(["a-vhost"], %{}) == :ok
end

test "run: enabling deletion protection succeeds", context do
_ = @command.run([@vhost], context[:opts])
delete_vhost(@vhost)
add_vhost(@vhost)

assert @inverse_command.run([@vhost], context[:opts]) == :ok
vh = find_vhost(@vhost)
assert vh[:protected_from_deletion]

assert @command.run([@vhost], context[:opts]) == :ok
vh = find_vhost(@vhost)
assert !vh[:protected_from_deletion]

delete_vhost(@vhost)
end

test "run: attempt to use a non-existent virtual host fails", context do
vh = "a-non-existent-3882-vhost"

assert match?(
{:error, {:no_such_vhost, _}},
@command.run([vh], Map.merge(context[:opts], %{}))
)
end

test "run: attempt to use an unreachable node returns a nodedown" do
opts = %{node: :jake@thedog, timeout: 200, description: "does not matter"}
assert match?({:badrpc, _}, @command.run(["na"], opts))
end

test "banner", context do
assert @command.banner([@vhost], context[:opts]) =~
~r/Removing deletion protection/
end
end
Original file line number Diff line number Diff line change
@@ -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-2025 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved.

defmodule EnableVhostDeletionProtectionCommandTest do
use ExUnit.Case, async: false
import TestHelper

@command RabbitMQ.CLI.Ctl.Commands.EnableVhostDeletionProtectionCommand
@inverse_command RabbitMQ.CLI.Ctl.Commands.DisableVhostDeletionProtectionCommand
@vhost "enable-vhost-deletion-protection"

setup_all do
RabbitMQ.CLI.Core.Distribution.start()
{:ok, opts: %{node: get_rabbit_hostname()}}
end

setup context do
on_exit(context, fn -> delete_vhost(context[:vhost]) end)
:ok
end

test "validate: no arguments fails validation" do
assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
end

test "validate: too many arguments fails validation" do
assert @command.validate(["test", "extra"], %{}) == {:validation_failure, :too_many_args}
end

test "validate: virtual host name without options fails validation" do
assert @command.validate(["a-vhost"], %{}) == :ok
end

test "run: enabling deletion protection succeeds", context do
add_vhost(@vhost)

assert @command.run([@vhost], context[:opts]) == :ok
vh = find_vhost(@vhost)
assert vh[:protected_from_deletion]

assert @inverse_command.run([@vhost], context[:opts]) == :ok
vh = find_vhost(@vhost)
assert !vh[:protected_from_deletion]

delete_vhost(@vhost)
end

test "run: attempt to use a non-existent virtual host fails", context do
vh = "a-non-existent-3882-vhost"

assert match?(
{:error, {:no_such_vhost, _}},
@command.run([vh], Map.merge(context[:opts], %{}))
)
end

test "run: attempt to use an unreachable node returns a nodedown" do
opts = %{node: :jake@thedog, timeout: 200, description: "does not matter"}
assert match?({:badrpc, _}, @command.run(["na"], opts))
end

test "banner", context do
assert @command.banner([@vhost], context[:opts]) =~
~r/Protecting virtual host/
end
end
18 changes: 16 additions & 2 deletions deps/rabbitmq_cli/test/ctl/update_vhost_metadata_command_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ defmodule UpdateVhostMetadataCommandTest do
assert vh[:tags] == [:a1, :b2, :c3]
end

test "run: enabling and disabling deletion protection succeeds", context do
test "run: enabling deletion protection succeeds", context do
add_vhost(@vhost)

opts =
Expand All @@ -92,7 +92,21 @@ defmodule UpdateVhostMetadataCommandTest do

assert @command.run([@vhost], opts) == :ok
vh = find_vhost(@vhost)
assert vh[:tags] == [:my_tag]
assert vh[:protected_from_deletion]
end

test "run: disabling deletion protection succeeds", context do
add_vhost(@vhost)

opts =
Map.merge(context[:opts], %{
description: "Protected from deletion",
protected_from_deletion: false
})

assert @command.run([@vhost], opts) == :ok
vh = find_vhost(@vhost)
assert !vh[:protected_from_deletion]
end

test "run: vhost tags are coerced to a list", context do
Expand Down

0 comments on commit c4a8b70

Please sign in to comment.