Make it possible to update virtual host tags
Currently they can only be specified at creation time
This commit is contained in:
parent
6539ad7fb1
commit
a5373d71d6
|
|
@ -14,7 +14,7 @@
|
|||
-export([add/2, add/4, delete/2, exists/1, with/2, with_user_and_vhost/3, assert/1, update/2,
|
||||
set_limits/2, vhost_cluster_state/1, is_running_on_all_nodes/1, await_running_on_all_nodes/2,
|
||||
list/0, count/0, list_names/0, all/0]).
|
||||
-export([parse_tags/1, update_metadata/2, tag_with/2, untag_from/2]).
|
||||
-export([parse_tags/1, update_metadata/2, tag_with/2, untag_from/2, update_tags/2, update_tags/3]).
|
||||
-export([lookup/1]).
|
||||
-export([info/1, info/2, info_all/0, info_all/1, info_all/2, info_all/3]).
|
||||
-export([dir/1, msg_store_dir_path/1, msg_store_dir_wildcard/0]).
|
||||
|
|
@ -26,6 +26,9 @@
|
|||
%% API
|
||||
%%
|
||||
|
||||
-type vhost_tag() :: atom() | string() | binary().
|
||||
-export_type([vhost_tag/0]).
|
||||
|
||||
recover() ->
|
||||
%% Clear out remnants of old incarnation, in case we restarted
|
||||
%% faster than other nodes handled DOWN messages from us.
|
||||
|
|
@ -377,6 +380,39 @@ update_metadata(VHostName, Fun) ->
|
|||
vhost:set_metadata(Record, Meta)
|
||||
end).
|
||||
|
||||
-spec update_tags(vhost:name(), [vhost_tag()], rabbit_types:username()) -> vhost:vhost() | rabbit_types:ok_or_error(any()).
|
||||
update_tags(VHostName, Tags, ActingUser) ->
|
||||
ConvertedTags = [rabbit_data_coercion:to_atom(I) || I <- Tags],
|
||||
try
|
||||
R = rabbit_misc:execute_mnesia_transaction(fun() ->
|
||||
update_tags(VHostName, ConvertedTags)
|
||||
end),
|
||||
rabbit_log:info("Successfully set tags for virtual host '~s' to ~p", [VHostName, ConvertedTags]),
|
||||
rabbit_event:notify(vhost_tags_set, [{name, VHostName},
|
||||
{tags, ConvertedTags},
|
||||
{user_who_performed_action, ActingUser}]),
|
||||
R
|
||||
catch
|
||||
throw:{error, {no_such_vhost, _}} = Error ->
|
||||
rabbit_log:warning("Failed to set tags for virtual host '~s': the virtual host does not exist", [VHostName]),
|
||||
throw(Error);
|
||||
throw:Error ->
|
||||
rabbit_log:warning("Failed to set tags for virtual host '~s': ~p", [VHostName, Error]),
|
||||
throw(Error);
|
||||
exit:Error ->
|
||||
rabbit_log:warning("Failed to set tags for virtual host '~s': ~p", [VHostName, Error]),
|
||||
exit(Error)
|
||||
end.
|
||||
|
||||
-spec update_tags(vhost:name(), [vhost_tag()]) -> vhost:vhost() | rabbit_types:ok_or_error(any()).
|
||||
update_tags(VHostName, Tags) ->
|
||||
ConvertedTags = [rabbit_data_coercion:to_atom(I) || I <- Tags],
|
||||
update(VHostName, fun(Record) ->
|
||||
Meta0 = vhost:get_metadata(Record),
|
||||
Meta = maps:update(tags, ConvertedTags, Meta0),
|
||||
vhost:set_metadata(Record, Meta)
|
||||
end).
|
||||
|
||||
-spec tag_with(vhost:name(), [atom()]) -> vhost:vhost() | rabbit_types:ok_or_error(any()).
|
||||
tag_with(VHostName, Tags) when is_list(Tags) ->
|
||||
update_metadata(VHostName, fun(#{tags := Tags0} = Meta) ->
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
## 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-2021 VMware, Inc. or its affiliates. All rights reserved.
|
||||
|
||||
defmodule RabbitMQ.CLI.Ctl.Commands.SetVhostTagsCommand do
|
||||
alias RabbitMQ.CLI.Core.{DocGuide, ExitCodes, Helpers}
|
||||
|
||||
@behaviour RabbitMQ.CLI.CommandBehaviour
|
||||
|
||||
def merge_defaults(args, opts), do: {args, opts}
|
||||
|
||||
def validate([], _) do
|
||||
{:validation_failure, :not_enough_args}
|
||||
end
|
||||
def validate(_, _), do: :ok
|
||||
|
||||
use RabbitMQ.CLI.Core.RequiresRabbitAppRunning
|
||||
|
||||
def run([vhost | tags], %{node: node_name}) do
|
||||
case :rabbit_misc.rpc_call(
|
||||
node_name, :rabbit_vhost, :update_tags, [vhost, tags, Helpers.cli_acting_user()]) do
|
||||
{:error, _} = err -> err
|
||||
{:badrpc, _} = err -> err
|
||||
_ -> :ok
|
||||
end
|
||||
end
|
||||
|
||||
def output({:error, {:no_such_vhost, vhost}}, %{node: node_name, formatter: "json"}) do
|
||||
{:error, %{"result" => "error", "node" => node_name, "message" => "Virtual host \"#{vhost}\" does not exists"}}
|
||||
end
|
||||
def output({:error, {:no_such_vhost, vhost}}, _) do
|
||||
{:error, ExitCodes.exit_dataerr(), "Virtual host \"#{vhost}\" does not exist"}
|
||||
end
|
||||
use RabbitMQ.CLI.DefaultOutput
|
||||
|
||||
def usage, do: "set_vhost_tags <vhost> <tag> [...]"
|
||||
|
||||
def usage_additional() do
|
||||
[
|
||||
["<vhost>", "Self-explanatory"],
|
||||
["<tags>", "Space separated list of tags"]
|
||||
]
|
||||
end
|
||||
|
||||
def usage_doc_guides() do
|
||||
[
|
||||
DocGuide.virtual_hosts()
|
||||
]
|
||||
end
|
||||
|
||||
def help_section(), do: :virtual_hosts
|
||||
|
||||
def description(), do: "Sets virtual host tags"
|
||||
|
||||
def banner([vhost | tags], _) do
|
||||
"Setting tags for virtual host \"#{vhost}\" to [#{tags |> Enum.join(", ")}] ..."
|
||||
end
|
||||
end
|
||||
|
|
@ -40,10 +40,10 @@ defmodule SetUserTagsCommandTest do
|
|||
test "run: throws a badrpc when instructed to contact an unreachable RabbitMQ node" do
|
||||
opts = %{node: :jake@thedog, timeout: 200}
|
||||
|
||||
assert match?({:badrpc, _}, @command.run([@user, :imperator], opts))
|
||||
assert match?({:badrpc, _}, @command.run([@user, :emperor], opts))
|
||||
end
|
||||
|
||||
@tag user: @user, tags: [:imperator]
|
||||
@tag user: @user, tags: [:emperor]
|
||||
test "run: on a single optional argument, add a flag to the user", context do
|
||||
@command.run(
|
||||
[context[:user] | context[:tags]],
|
||||
|
|
@ -58,16 +58,16 @@ defmodule SetUserTagsCommandTest do
|
|||
assert result[:tags] == context[:tags]
|
||||
end
|
||||
|
||||
@tag user: "interloper", tags: [:imperator]
|
||||
test "run: on an invalid user, get a no such user error", context do
|
||||
@tag user: "interloper", tags: [:emperor]
|
||||
test "run: when user does not exist, returns an error", context do
|
||||
assert @command.run(
|
||||
[context[:user] | context[:tags]],
|
||||
context[:opts]
|
||||
) == {:error, {:no_such_user, context[:user]}}
|
||||
end
|
||||
|
||||
@tag user: @user, tags: [:imperator, :generalissimo]
|
||||
test "run: on multiple optional arguments, add all flags to the user", context do
|
||||
@tag user: @user, tags: [:emperor, :generalissimo]
|
||||
test "run: with multiple optional arguments, adds multiple tags", context do
|
||||
@command.run(
|
||||
[context[:user] | context[:tags]],
|
||||
context[:opts]
|
||||
|
|
@ -81,8 +81,8 @@ defmodule SetUserTagsCommandTest do
|
|||
assert result[:tags] == context[:tags]
|
||||
end
|
||||
|
||||
@tag user: @user, tags: [:imperator]
|
||||
test "run: with no optional arguments, clear user tags", context do
|
||||
@tag user: @user, tags: [:emperor]
|
||||
test "run: without optional arguments, clears user tags", context do
|
||||
|
||||
set_user_tags(context[:user], context[:tags])
|
||||
|
||||
|
|
@ -96,7 +96,7 @@ defmodule SetUserTagsCommandTest do
|
|||
assert result[:tags] == []
|
||||
end
|
||||
|
||||
@tag user: @user, tags: [:imperator]
|
||||
@tag user: @user, tags: [:emperor]
|
||||
test "run: identical calls are idempotent", context do
|
||||
|
||||
set_user_tags(context[:user], context[:tags])
|
||||
|
|
@ -114,8 +114,8 @@ defmodule SetUserTagsCommandTest do
|
|||
assert result[:tags] == context[:tags]
|
||||
end
|
||||
|
||||
@tag user: @user, old_tags: [:imperator], new_tags: [:generalissimo]
|
||||
test "run: if different tags exist, overwrite them", context do
|
||||
@tag user: @user, old_tags: [:emperor], new_tags: [:generalissimo]
|
||||
test "run: overwrites existing tags", context do
|
||||
|
||||
set_user_tags(context[:user], context[:old_tags])
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,139 @@
|
|||
## 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 SetVhostTagsCommandTest do
|
||||
use ExUnit.Case, async: false
|
||||
import TestHelper
|
||||
|
||||
@command RabbitMQ.CLI.Ctl.Commands.SetVhostTagsCommand
|
||||
|
||||
@vhost "vhost99-tests"
|
||||
|
||||
setup_all do
|
||||
RabbitMQ.CLI.Core.Distribution.start()
|
||||
|
||||
add_vhost(@vhost)
|
||||
|
||||
on_exit([], fn ->
|
||||
delete_vhost(@vhost)
|
||||
end)
|
||||
|
||||
:ok
|
||||
end
|
||||
|
||||
setup context do
|
||||
add_vhost(context[:vhost])
|
||||
on_exit([], fn -> delete_vhost(context[:vhost]) end)
|
||||
|
||||
{:ok, opts: %{node: get_rabbit_hostname()}}
|
||||
end
|
||||
|
||||
test "validate: on an incorrect number of arguments, returns an error" do
|
||||
assert @command.validate([], %{}) == {:validation_failure, :not_enough_args}
|
||||
end
|
||||
|
||||
test "run: throws a badrpc when instructed to contact an unreachable RabbitMQ node" do
|
||||
opts = %{node: :jake@thedog, timeout: 200}
|
||||
|
||||
assert match?({:badrpc, _}, @command.run([@vhost, :qa], opts))
|
||||
end
|
||||
|
||||
@tag vhost: @vhost
|
||||
test "run: with a single optional argument, adds a single tag", context do
|
||||
@command.run([context[:vhost], :qa], context[:opts])
|
||||
|
||||
result = Enum.find(
|
||||
list_vhosts(),
|
||||
fn(record) -> record[:vhost] == context[:vhost] end
|
||||
)
|
||||
|
||||
assert result[:tags] == context[:tags]
|
||||
end
|
||||
|
||||
@tag vhost: "non/ex1st3nT"
|
||||
test "run: when virtual host does not exist, reports an error", context do
|
||||
delete_vhost(context[:vhost])
|
||||
|
||||
assert @command.run(
|
||||
[context[:vhost]],
|
||||
context[:opts]
|
||||
) == {:error, {:no_such_vhost, context[:vhost]}}
|
||||
end
|
||||
|
||||
@tag user: @vhost, tags: [:qa, :limited]
|
||||
test "run: with multiple optional arguments, adds multiple tags", context do
|
||||
@command.run(
|
||||
[context[:vhost] | context[:tags]],
|
||||
context[:opts]
|
||||
)
|
||||
|
||||
result = Enum.find(
|
||||
list_vhosts(),
|
||||
fn(record) -> record[:vhost] == context[:vhost] end
|
||||
)
|
||||
|
||||
assert result[:tags] == context[:tags]
|
||||
end
|
||||
|
||||
@tag user: @vhost, tags: [:qa]
|
||||
test "run: with no optional arguments, clears virtual host tags", context do
|
||||
set_vhost_tags(context[:vhost], context[:tags])
|
||||
|
||||
@command.run([context[:vhost]], context[:opts])
|
||||
|
||||
result = Enum.find(
|
||||
list_vhosts(),
|
||||
fn(record) -> record[:vhost] == context[:vhost] end
|
||||
)
|
||||
|
||||
assert result[:tags] == []
|
||||
end
|
||||
|
||||
@tag user: @vhost, tags: [:qa]
|
||||
test "run: identical calls are idempotent", context do
|
||||
set_vhost_tags(context[:vhost], context[:tags])
|
||||
|
||||
assert @command.run(
|
||||
[context[:vhost] | context[:tags]],
|
||||
context[:opts]
|
||||
) == :ok
|
||||
|
||||
result = Enum.find(
|
||||
list_vhosts(),
|
||||
fn(record) -> record[:vhost] == context[:vhost] end
|
||||
)
|
||||
|
||||
assert result[:tags] == context[:tags]
|
||||
end
|
||||
|
||||
@tag user: @vhost, old_tags: [:qa], new_tags: [:limited]
|
||||
test "run: overwrites existing tags them", context do
|
||||
set_vhost_tags(context[:vhost], context[:old_tags])
|
||||
|
||||
assert @command.run(
|
||||
[context[:vhost] | context[:new_tags]],
|
||||
context[:opts]
|
||||
) == :ok
|
||||
|
||||
result = Enum.find(
|
||||
list_vhosts(),
|
||||
fn(record) -> record[:vhost] == context[:vhost] end
|
||||
)
|
||||
|
||||
assert result[:tags] == context[:new_tags]
|
||||
end
|
||||
|
||||
@tag user: @vhost, tags: ["abc"]
|
||||
test "banner", context do
|
||||
assert @command.banner(
|
||||
[context[:vhost] | context[:tags]],
|
||||
context[:opts]
|
||||
)
|
||||
=~ ~r/Setting tags for virtual host \"#{context[:vhost]}\" to \[#{context[:tags]}\] \.\.\./
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -86,8 +86,11 @@ defmodule TestHelper do
|
|||
end
|
||||
|
||||
def set_user_tags(name, tags) do
|
||||
:rpc.call(get_rabbit_hostname(), :rabbit_auth_backend_internal, :set_tags,
|
||||
[name, tags, "acting-user"])
|
||||
:rpc.call(get_rabbit_hostname(), :rabbit_auth_backend_internal, :set_tags, [name, tags, "acting-user"])
|
||||
end
|
||||
|
||||
def set_vhost_tags(name, tags) do
|
||||
:rpc.call(get_rabbit_hostname(), :rabbit_vhost, :update_tags, [name, tags, "acting-user"])
|
||||
end
|
||||
|
||||
def authenticate_user(name, password) do
|
||||
|
|
|
|||
Loading…
Reference in New Issue