1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
## 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) 2016-2022 VMware, Inc. or its affiliates. All rights reserved.
defmodule RabbitMQ.CLI.Core.Distribution do
alias RabbitMQ.CLI.Core.{ANSI, Config, Helpers}
#
# API
#
def start() do
start(%{})
end
def start(options) do
node_name_type = Config.get_option(:longnames, options)
result = start(node_name_type, 10, :undefined)
ensure_cookie(options)
result
end
def stop, do: Node.stop()
def start_as(node_name, options) do
node_name_type = Config.get_option(:longnames, options)
result = start_with_epmd(node_name, node_name_type)
ensure_cookie(options)
result
end
## Optimization. We try to start EPMD only if distribution fails
def start_with_epmd(node_name, node_name_type) do
case Node.start(node_name, node_name_type) do
{:ok, _} = ok ->
ok
{:error, {:already_started, _}} = started ->
started
{:error, {{:already_started, _}, _}} = started ->
started
## EPMD can be stopped. Retry with EPMD
{:error, _} ->
:rabbit_nodes_common.ensure_epmd()
Node.start(node_name, node_name_type)
end
end
def per_node_timeout(:infinity, _) do
:infinity
end
def per_node_timeout(timeout, node_count) do
Kernel.trunc(timeout / node_count)
end
#
# Implementation
#
def ensure_cookie(options) do
case Config.get_option(:erlang_cookie, options) do
nil ->
:ok
cookie ->
Node.set_cookie(cookie)
maybe_warn_about_deprecated_rabbitmq_erlang_cookie_env_variable(options)
:ok
end
end
defp start(_opt, 0, last_err) do
{:error, last_err}
end
defp start(node_name_type, attempts, _last_err) do
candidate = generate_cli_node_name(node_name_type)
case start_with_epmd(candidate, node_name_type) do
{:ok, _} ->
:ok
{:error, {:already_started, pid}} ->
{:ok, pid}
{:error, {{:already_started, pid}, _}} ->
{:ok, pid}
{:error, reason} ->
start(node_name_type, attempts - 1, reason)
end
end
defp generate_cli_node_name(node_name_type) do
case Helpers.get_rabbit_hostname(node_name_type) do
{:error, _} = err ->
throw(err)
rmq_hostname ->
# This limits the number of possible unique node names used by CLI tools to avoid
# the atom table from growing above the node limit. We must use reasonably unique IDs
# to allow for concurrent CLI tool execution.
#
# Enum.random/1 is constant time and space with range arguments https://hexdocs.pm/elixir/Enum.html#random/1.
id = Enum.random(1..1024)
String.to_atom("rabbitmqcli-#{id}-#{rmq_hostname}")
end
end
defp maybe_warn_about_deprecated_rabbitmq_erlang_cookie_env_variable(options) do
case System.get_env("RABBITMQ_ERLANG_COOKIE") do
nil ->
:ok
_ ->
case Config.output_less?(options) do
true ->
:ok
false ->
warning =
ANSI.bright_red(
"RABBITMQ_ERLANG_COOKIE env variable support is deprecated and will be REMOVED in a future version. "
) <>
ANSI.yellow(
"Use the $HOME/.erlang.cookie file or the --erlang-cookie switch instead."
)
IO.puts(warning)
end
end
end
end
|