Skip to content

Commit

Permalink
CLI: list_deprecated_features command
Browse files Browse the repository at this point in the history
Lists all or used deprecated features
  • Loading branch information
dcorbacho committed Nov 10, 2023
1 parent 5b18e9d commit 4e720a0
Show file tree
Hide file tree
Showing 3 changed files with 195 additions and 0 deletions.
62 changes: 62 additions & 0 deletions deps/rabbit/src/rabbit_deprecated_feature_extra.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
%% 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 2018-2023 VMware, Inc. or its affiliates.
%%
%% @doc
%% This module provides extra functions unused by the feature flags
%% subsystem core functionality.

-module(rabbit_deprecated_feature_extra).

-export([cli_info/1]).

-type cli_info() :: [cli_info_entry()].
%% A list of deprecated feature properties, formatted for the RabbitMQ CLI.

-type cli_info_entry() :: [{name, rabbit_feature_flags:feature_name()} |
{deprecation_phase, rabbit_deprecated_feature:deprecation_phase()} |
{provided_by, atom()} |
{desc, string()} |
{doc_url, string()}].
%% A list of properties for a single deprecated feature, formatted for the
%% RabbitMQ CLI.

-spec cli_info(Which :: all | used) -> cli_info().
%% @doc
%% Returns a list of all or used deprecated features properties, depending on the argument.
%%
%% @param Which The group of deprecated features to return: `all' or `used'.
%% @returns the list of all deprecated feature properties.

cli_info(all) ->
cli_info0(rabbit_deprecated_features:list(all));
cli_info(used) ->
cli_info0(rabbit_deprecated_features:list(used)).

-spec cli_info0(rabbit_feature_flags:feature_flags()) -> cli_info().
%% @doc
%% Formats a map of deprecated features and their properties into a list of
%% deprecated feature properties as expected by the RabbitMQ CLI.
%%
%% @param DeprecatedFeatures A map of deprecated features.
%% @returns the list of deprecated features properties, created from the map
%% specified in arguments.

cli_info0(DeprecatedFeature) ->
lists:foldr(
fun(FeatureName, Acc) ->
FeatureProps = maps:get(FeatureName, DeprecatedFeature),

App = maps:get(provided_by, FeatureProps),
DeprecationPhase = maps:get(deprecation_phase, FeatureProps, ""),
Desc = maps:get(desc, FeatureProps, ""),
DocUrl = maps:get(doc_url, FeatureProps, ""),
Info = [{name, FeatureName},
{desc, unicode:characters_to_binary(Desc)},
{deprecation_phase, DeprecationPhase},
{doc_url, unicode:characters_to_binary(DocUrl)},
{provided_by, App}],
[Info | Acc]
end, [], lists:sort(maps:keys(DeprecatedFeature))).
25 changes: 25 additions & 0 deletions deps/rabbit/src/rabbit_deprecated_features.erl
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@
-export([extend_properties/2,
should_be_permitted/2,
enable_underlying_feature_flag_cb/1]).
-export([list/1]).

-type deprecated_feature_modattr() :: {rabbit_feature_flags:feature_name(),
feature_props()}.
Expand Down Expand Up @@ -346,6 +347,25 @@ get_warning(FeatureProps, Permitted) when is_map(FeatureProps) ->
maps:get(when_removed, Msgs)
end.

-spec list(Which :: all | used) -> rabbit_feature_flags:feature_flags().
%% @doc
%% Lists all or used deprecated features, depending on the argument.
%%
%% @param Which The group of deprecated features to return: `all' or `used'.
%% @returns A map of selected deprecated features.

list(all) ->
maps:filter(
fun(_, FeatureProps) -> ?IS_DEPRECATION(FeatureProps) end,
rabbit_ff_registry_wrapper:list(all));
list(used) ->
maps:filter(
fun(_, FeatureProps) -> ?IS_DEPRECATION(FeatureProps)
and
is_deprecated_feature_in_use(FeatureProps)
end,
rabbit_ff_registry_wrapper:list(all)).

%% -------------------------------------------------------------------
%% Internal functions.
%% -------------------------------------------------------------------
Expand Down Expand Up @@ -602,3 +622,8 @@ enable_underlying_feature_flag_cb(
_ ->
ok
end.

is_deprecated_feature_in_use(#{callbacks := #{is_feature_used := {CallbackMod, CallbackFun}}}) ->
erlang:apply(CallbackMod, CallbackFun, [#{}]);
is_deprecated_feature_in_use(_) ->
false.
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
## 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) 2018-2023 VMware, Inc. or its affiliates. All rights reserved.

defmodule RabbitMQ.CLI.Ctl.Commands.ListDeprecatedFeaturesCommand do
alias RabbitMQ.CLI.Core.{DocGuide, Validators}
alias RabbitMQ.CLI.Ctl.InfoKeys

@behaviour RabbitMQ.CLI.CommandBehaviour
use RabbitMQ.CLI.DefaultOutput

def formatter(), do: RabbitMQ.CLI.Formatters.Table

@info_keys ~w(name deprecation_phase provided_by desc doc_url)a

def info_keys(), do: @info_keys

def scopes(), do: [:ctl, :diagnostics]

def switches(), do: [used: :boolean]

def merge_defaults([], opts) do
{["name", "deprecation_phase"], Map.merge(%{used: false}, opts)}
end
def merge_defaults(args, opts) do
{args, Map.merge(%{used: false}, opts)}
end

def validate(args, _) do
case InfoKeys.validate_info_keys(args, @info_keys) do
{:ok, _} -> :ok
err -> err
end
end

def validate_execution_environment(args, opts) do
Validators.chain(
[
&Validators.rabbit_is_loaded/2,
&Validators.rabbit_is_running/2
],
[args, opts]
)
end

def run([_ | _] = args, %{node: node_name, timeout: timeout, used: false}) do
case :rabbit_misc.rpc_call(node_name, :rabbit_deprecated_feature_extra, :cli_info, [:all], timeout) do
# Server does not support deprecated features, consider none are available.
{:badrpc, {:EXIT, {:undef, _}}} -> []
{:badrpc, _} = err -> err
val -> filter_by_arg(val, args)
end
end
def run([_ | _] = args, %{node: node_name, timeout: timeout, used: true}) do
case :rabbit_misc.rpc_call(node_name, :rabbit_deprecated_feature_extra, :cli_info, [:used], timeout) do
# Server does not support deprecated features, consider none are available.
{:badrpc, {:EXIT, {:undef, _}}} -> []
{:badrpc, _} = err -> err
val -> filter_by_arg(val, args)
end
end

def banner(_, %{used: false}), do: "Listing deprecated features ..."
def banner(_, %{used: true}), do: "Listing deprecated features in use ..."

def usage, do: "list_deprecated_features [--used] [<column> ...]"

def usage_additional() do
[
["<column>", "must be one of " <> Enum.join(Enum.sort(@info_keys), ", ")],
["--used", "returns deprecated features in use"]
]
end

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

def help_section(), do: :feature_flags

def description(), do: "Lists deprecated features"

#
# Implementation
#

defp filter_by_arg(ff_info, _) when is_tuple(ff_info) do
# tuple means unexpected data
ff_info
end

defp filter_by_arg(ff_info, [_ | _] = args) when is_list(ff_info) do
symbol_args = InfoKeys.prepare_info_keys(args)

Enum.map(
ff_info,
fn ff ->
symbol_args
|> Enum.filter(fn arg -> ff[arg] != nil end)
|> Enum.map(fn arg -> {arg, ff[arg]} end)
end
)
end
end

0 comments on commit 4e720a0

Please sign in to comment.