1## This Source Code Form is subject to the terms of the Mozilla Public 2## License, v. 2.0. If a copy of the MPL was not distributed with this 3## file, You can obtain one at https://mozilla.org/MPL/2.0/. 4## 5## Copyright (c) 2007-2021 VMware, Inc. or its affiliates. All rights reserved. 6 7defmodule RabbitMQ.CLI.Plugins.Commands.DisableCommand do 8 alias RabbitMQ.CLI.Plugins.Helpers, as: PluginHelpers 9 alias RabbitMQ.CLI.Core.{DocGuide, Validators} 10 import RabbitMQ.CLI.Core.{CodePath, Paths} 11 12 @behaviour RabbitMQ.CLI.CommandBehaviour 13 14 def formatter(), do: RabbitMQ.CLI.Formatters.Plugins 15 16 def merge_defaults(args, opts) do 17 {args, Map.merge(%{online: false, offline: false, all: false}, opts)} 18 end 19 20 def distribution(%{offline: true}), do: :none 21 def distribution(%{offline: false}), do: :cli 22 23 def switches(), do: [online: :boolean, offline: :boolean, all: :boolean] 24 25 def validate([], %{all: false}) do 26 {:validation_failure, :not_enough_args} 27 end 28 29 def validate([_ | _], %{all: true}) do 30 {:validation_failure, {:bad_argument, "Cannot set both --all and a list of plugins"}} 31 end 32 33 def validate(_, %{online: true, offline: true}) do 34 {:validation_failure, {:bad_argument, "Cannot set both online and offline"}} 35 end 36 37 def validate(_args, _opts) do 38 :ok 39 end 40 41 def validate_execution_environment(args, opts) do 42 Validators.chain( 43 [ 44 &PluginHelpers.can_set_plugins_with_mode/2, 45 &require_rabbit_and_plugins/2, 46 &PluginHelpers.enabled_plugins_file/2, 47 &plugins_dir/2 48 ], 49 [args, opts] 50 ) 51 end 52 53 def run(plugin_names, %{all: all_flag, node: node_name} = opts) do 54 plugins = 55 case all_flag do 56 false -> for s <- plugin_names, do: String.to_atom(s) 57 true -> PluginHelpers.plugin_names(PluginHelpers.list(opts)) 58 end 59 60 enabled = PluginHelpers.read_enabled(opts) 61 all = PluginHelpers.list(opts) 62 implicit = :rabbit_plugins.dependencies(false, enabled, all) 63 to_disable_deps = :rabbit_plugins.dependencies(true, plugins, all) 64 plugins_to_set = MapSet.difference(MapSet.new(enabled), MapSet.new(to_disable_deps)) 65 66 mode = PluginHelpers.mode(opts) 67 68 case PluginHelpers.set_enabled_plugins(MapSet.to_list(plugins_to_set), opts) do 69 {:ok, enabled_plugins} -> 70 {:stream, 71 Stream.concat([ 72 [:rabbit_plugins.strictly_plugins(enabled_plugins, all)], 73 RabbitMQ.CLI.Core.Helpers.defer(fn -> 74 :timer.sleep(5000) 75 76 case PluginHelpers.update_enabled_plugins(enabled_plugins, mode, node_name, opts) do 77 %{set: new_enabled} = result -> 78 disabled = implicit -- new_enabled 79 80 filter_strictly_plugins( 81 Map.put(result, :disabled, :rabbit_plugins.strictly_plugins(disabled, all)), 82 all, 83 [:set, :started, :stopped] 84 ) 85 86 other -> 87 other 88 end 89 end) 90 ])} 91 92 {:error, _} = err -> 93 err 94 end 95 end 96 97 use RabbitMQ.CLI.Plugins.ErrorOutput 98 99 def banner([], %{all: true, node: node_name}) do 100 "Disabling ALL plugins on node #{node_name}" 101 end 102 103 def banner(plugins, %{node: node_name}) do 104 ["Disabling plugins on node #{node_name}:" | plugins] 105 end 106 107 def usage, do: "disable <plugin1> [ <plugin2>] | --all [--offline] [--online]" 108 109 def usage_additional() do 110 [ 111 ["<plugin1> [ <plugin2>]", "names of plugins to disable separated by a space"], 112 ["--online", "contact target node to disable the plugins. Changes are applied immediately."], 113 ["--offline", "update enabled plugins file directly without contacting target node. Changes will be delayed until the node is restarted."], 114 ["--all", "disable all currently enabled plugins"] 115 ] 116 end 117 118 def usage_doc_guides() do 119 [ 120 DocGuide.plugins() 121 ] 122 end 123 124 def help_section(), do: :plugin_management 125 126 def description(), do: "Disables one or more plugins" 127 128 # 129 # Implementation 130 # 131 132 defp filter_strictly_plugins(map, _all, []) do 133 map 134 end 135 136 defp filter_strictly_plugins(map, all, [head | tail]) do 137 case map[head] do 138 nil -> 139 filter_strictly_plugins(map, all, tail) 140 141 other -> 142 value = :rabbit_plugins.strictly_plugins(other, all) 143 filter_strictly_plugins(Map.put(map, head, value), all, tail) 144 end 145 end 146end 147