GithubHelp home page GithubHelp logo

rabbitmq-cli's Introduction

RabbitMQ CLI Tools

This repository has been moved to the main unified RabbitMQ "monorepo", including all open issues. You can find the source under /deps/rabbitmq_cli. All issues have been transferred.

Overview

Build Status

This repository contains RabbitMQ CLI tools (rabbitmqctl and others).

This generation of CLI tools first shipped with RabbitMQ 3.7.0.

Goals

Team RabbitMQ wanted a set of tools that

  • Was extensible from/with plugins
  • Supported pluggable output formats (in particular machine-friendly ones)
  • Had good test coverage
  • Wasn't as coupled to the server repository
  • Could be used as a low risk vehicle for Elixir evaluation

Supported RabbitMQ Versions

Long lived branches in this repository track the same branch in RabbitMQ core and related repositories. So master tracks master in rabbitmq-server, v3.7.x tracks branch v3.7.x in rabbitmq-server and so on.

Please use the version of CLI tools that come with the RabbitMQ distribution version installed.

Building

Requirements

Building this project requires

  • Erlang/OTP 21.3 (or later)
  • Elixir 1.10.0 (or later).

Command line tools depend on rabbitmq-common. Dependencies are being resolved by erlang.mk

Building Standalone Executables

This repo produces a rabbitmqctl executable which can be used as different tools (rabbitmq-plugins, rabbitmq-diagnostics, rabbitmq-queues, rabbitmq-streams, rabbitmq-upgrade) by copying or symlinking it with different names. Depending on the name, a different set of commands will be loaded and available, including for --help.

To generate the executable, run

make

Usage

rabbitmqctl

See rabbitmqctl help and rabbitmqctl man page for details.

rabbitmq-plugins

See rabbitmq-plugins help and rabbitmq-plugins man page for details.

rabbitmq-diagnostics

See rabbitmq-diagnostics help and rabbitmq-diagnostics man page.

Testing

See CONTRIBUTING.md.

Developing

Adding a New Command

Conventions

RabbitMQ CLI tools use module name conventions to match the command-line actions (commands) to modules. The convention is outlined in the CommandBehaviour module.

Command Module Interface

Each command module must implement the RabbitMQ.CLI.CommandBehaviour behaviour, which includes the following functions:

  • validate(args, opts), which returns either :ok or a tuple of {:validation_failure, failure_detail} where failure detail is typically one of: :too_many_args, :not_enough_args or {:bad_argument, String.t}.

  • merge_defaults(args, opts), which is used to return updated arguments and/or options.

  • run(args, opts), where the actual command is implemented. Here, args is a list of command-specific parameters and opts is a Map containing option flags.

  • usage, which returns a string describing the command, its arguments and its optional flags.

  • banner(args, opts), which returns a string to be printed before the command output.

There are also a number of optional callbacks:

  • switches, which returns command specific switches.
  • aliases, which returns a list of command aliases (if any).
  • formatter: what output formatter should be used by default.
  • usage_additional: extra values appended to the usage output to provide additional command-specific documentation.
  • scopes: what scopes this command appears in. Scopes associate tools (e.g. rabbitmqctl, rabbitmq-diagnostics, rabbitmq-queues, rabbitmq-streams) with commands.
  • distribution: control erlang distribution. Can be :cli (default), :none or {:fun, fun}

Tutorial

We have a tutorial that demonstrates how to add a CLI command that deletes a queue.

Examples

See lib/rabbitmq/cli/ctl/commands/status_command.ex and test/status_command_test.exs for minimalistic but not entirely trivial examples.

Copyright and License

The project is licensed under the MPL, the same license as RabbitMQ.

(c) 2007-2020 VMware, Inc. or its affiliates.

rabbitmq-cli's People

Contributors

acogoluegnes avatar anupamasingh10 avatar ayanda-d avatar bdshroyer avatar binarin avatar camelpunch avatar dcorbacho avatar dumbbell avatar gerhard avatar gmile avatar gsantomaggio avatar hairyhum avatar hallazzang avatar jsoref avatar kjnilsson avatar lukebakken avatar michaelklishin avatar milmazz avatar peter-awesome avatar pjk25 avatar potatosalad avatar rossjones avatar samnela avatar spring-operator avatar whitespirit0 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rabbitmq-cli's Issues

Start rabbitmqctl nodes with unique name

Currently it's not possible to run two rabbitmqctl instances at the same time (e.g. sync_queue and another one to test cancel_sync_queue) because all instances use the same name.

This issue is not as trivial as it may seem and it took a few iterations in the current rabbitmqctl, see rabbitmq/rabbitmq-server#549 for the most recent one.

Create generic error handler

Currently the main module is vulnerable to unusual error returns (e.g. :error_string instead of :error). This could be dealt with via an error parser that checks the output and runs a simple conversion on any returns it doesn't understand: ```{:strange_code, } -> {:error, {:strange_code, }}`. Many commands already follow this format already, so the CLI knows how to handle it.

Introduce a rate control flag to rabbitmqctl (for list_* commands)

Following the implemention of #62, there could be need to introduce some level of control to the rate at which information is returned and displayed when rabbitmqctl list_* commands are executed.

For example during troubleshooting, controlled monitoring and inspection of a node's metadata like queues and bindings in real time, while the node is subject to other factors like queue declarations, publishes, e.t.c.

list_bindings throw FunctionClauseError when no vhost specificed

** (FunctionClauseError) no function clause matching in ListBindingsCommand.banner/2
    (rabbitmqctl) lib/list_bindings_command.ex:66: ListBindingsCommand.banner(["source_name", "source_kind", "destination_name", "destination_kind", "routing_key", "arguments"], %{node: :rabbit@snowman, timeout: :infinity, vhost: "/"})
    (rabbitmqctl) lib/rabbitmqctl.ex:79: RabbitMQCtl.print_banner/3
    (rabbitmqctl) lib/rabbitmqctl.ex:63: anonymous fn/4 in RabbitMQCtl.run_command/2
    (rabbitmqctl) lib/rabbitmqctl.ex:32: RabbitMQCtl.main/1
    (elixir) lib/kernel/cli.ex:76: anonymous fn/3 in Kernel.CLI.exec_fun/2```

Non default vhost is overriden in merge_defaults

merge_defaults in most commands is implemented like Map.merge(opts, default_opts), which always rewrites opts with default_opts making impossible to set custom vhost or other params.

There should be tests for merge_defaults.

Example test:

test "merge_defaults: default vhost is '/'" do
  assert @command.merge_defaults([], %{}) == {[], %{vhost: "/"}}
  assert @command.merge_defaults([], %{vhost: "non_default"}) == {[], %{vhost: "non_default"}}
end

Refactor RabbitMQCtl to evaluate command strings

The Elixir.Code module makes it fairly easy to generate and evaluate strings as function calls. If we use this in RabbitMQCtl.main/1, we can just define one module per subcommand (e.g., EnvironmentCommand for rabbitmqctl env) instead of making one handler in main for each subcommand. As long as we're consistent with the structure of these modules, we can do this fairly simply.

Support machine-friendly output formats

Our CLI tools should be able to output multiple formats for both humans and machines consumption.

The simplest use case is the combination with Unix commands, such as cut(1) or awk(1). Lists and tables should formatted with easy integration with those tools in mind.

A more advanced example is what is done with libxo: it is used by standard Unix tools to format XML, JSON or HTML, in addition to the expected human-readable output.

Finally, on Windows, PowerShell offers commands the possibility to exchange "objects", skipping parsing entirely if I understand correctly. I have no idea how it works but it seems powerful.

Runtime error when first command-line argument is an invalid option

./rabbitmqctl --nope foo clear_permissions -q foo 
Error: invalid options for this command.
Given:
    --nope foo clear_permissions -q foo
** (SyntaxError) nofile:1: syntax error before: '.'
    (elixir) lib/code.ex:168: Code.eval_string/3
    (rabbitmqctl) lib/rabbitmqctl.ex:65: RabbitMQCtl.command_usage/1
    (rabbitmqctl) lib/rabbitmqctl.ex:112: RabbitMQCtl.print_standard_messages/2
    (rabbitmqctl) lib/rabbitmqctl.ex:33: RabbitMQCtl.main/1
    (elixir) lib/kernel/cli.ex:76: anonymous fn/3 in Kernel.CLI.exec_fun/2

This should just fail and print an error message.

Fix flaky list_users spec

The spec for the list_users command intermittently fails with the following message:

  1) test On a successful query, return an array of lists of tuples (ListUsersCommandTest)
     test/list_users_command_test.exs:55
     Expected truthy, got false
     code: Enum.all?(matches_found, fn user -> Enum.find(context[:std_result], fn found -> found == user end) end)
     stacktrace:
       test/list_users_command_test.exs:59: anonymous fn/1 in ListUsersCommandTest.test On a successful query, return an array of lists of tuples/1
       (ex_unit) lib/ex_unit/capture_io.ex:146: ExUnit.CaptureIO.do_capture_io/2
       (ex_unit) lib/ex_unit/capture_io.ex:119: ExUnit.CaptureIO.do_capture_io/3
       test/list_users_command_test.exs:56

..

  2) test sufficiently long timeouts don't interfere with results (ListUsersCommandTest)
     test/list_users_command_test.exs:72
     Expected truthy, got false
     code: Enum.all?(matches_found, fn user -> Enum.find(context[:std_result], fn found -> found == user end) end)
     stacktrace:
       test/list_users_command_test.exs:77: anonymous fn/1 in ListUsersCommandTest.test sufficiently long timeouts don't interfere with results/1
       (ex_unit) lib/ex_unit/capture_io.ex:146: ExUnit.CaptureIO.do_capture_io/2
       (ex_unit) lib/ex_unit/capture_io.ex:119: ExUnit.CaptureIO.do_capture_io/3
       test/list_users_command_test.exs:74

command aliasing via an .ini file

A request from @dumbbell, this would allow us to set command aliases using a configuration file. Useful if we want to hand people some code for debugging purposes, but don't want them to have to use eval.

`rabbitmqctl forget_cluster_mode --offline` is missing lager_config

RABBITMQ_HOME="/path/to/umbrella.git/deps/rabbit/" RABBITMQ_MNESIA_DIR="/var/folders/6v/nzn6gr5d6k31r39x57fddtpm0000gp/T//rabbitmq-test-instances/rabbit/mnesia/rabbit" ./rabbitmqctl forget_cluster_node -n rabbit@mercurio hare@mercurio --offline
"Removing node hare@mercurio from the cluster"
  * Impersonating node: rabbit@mercurio...
 done
  * Mnesia directory: /var/folders/6v/nzn6gr5d6k31r39x57fddtpm0000gp/T/rabbitmq-test-instances/rabbit/mnesia/rabbit...

08:34:49.359 [info]  Application mnesia exited: :stopped
** (UndefinedFunctionError) function :lager_config.get/2 is undefined (module :lager_config is not available)
    :lager_config.get({:rabbit_log_lager_event, :loglevel}, {0, []})
    (rabbit) src/rabbit_mnesia.erl:308: :rabbit_mnesia.forget_cluster_node/2
    (rabbit) src/rabbit_mnesia.erl:333: :rabbit_mnesia.remove_node_offline_node/1
    (rabbitmqctl) lib/rabbitmqctl.ex:95: anonymous fn/4 in RabbitMQCtl.run_command/2
    (rabbitmqctl) lib/rabbitmqctl.ex:49: RabbitMQCtl.main/1
    (elixir) lib/kernel/cli.ex:76: anonymous fn/3 in Kernel.CLI.exec_fun/2

Improve integration testing for rabbitmqctl

We've been having a lot of command modules pass their tests, but crash when you try to run them from a compiled CLI. This means we need more in-depth integration testing.

Ideally the solution here will respect the goal of self-contained command code and testing, but with integration tests there may not be a clean way.

MVP for rabbitmqctl status

Fill in the functionality for the rabbitmqctl status command as a way to drive out some program structure.

Docker container for testing

AS A RabbitMQ developer
I WANT the CLI tests to run in a Docker container
SO THAT I don't have to install Elixir when I'm not working on the CLI

NOTE: This may be very slow relative to the actual tests. We may ultimately want a flag in there to let you run tests locally if you have Elixir installed.

Command specific error printing.

Some commands have specific error messages returned from run, which is not handled properly by rabbitmqctl module.
This messages should be handled by function in command module. Something like report_error or report_output.

Namespace all modules under RabbitMQ.CLI

Currently we use module names such as Parser (top-level). This repository is meant to have multiple tools and inevitably a small shared library they will use. We should namespace all modules under RabbitMQ.CLI, e.g. RabbitMQ.CLI.RabbitMQCtl, RabbitMQ.CLI.Distribution, RabbitMQ.CLI.RabbitMQCtl.Parser and so on.

Test suite assumes a single vhost

I have 2 vhosts in the RabbitMQ node I run mix test against and it looks like some tests assume there's a single vhost:

  9) test valid user returns a list of permissions (ListUserPermissionsCommandTest)
     test/list_user_permissions_command_test.exs:78
     Assertion with == failed
     code: ListUserPermissionsCommand.list_user_permissions([context[:username]], context[:opts]) == context[:result]
     lhs:  [[vhost: "bunny_testbed", configure: ".*", write: ".*", read: ".*"], [vhost: "/", configure: ".*", write: ".*", read: ".*"]]
     rhs:  [[vhost: "/", configure: ".*", write: ".*", read: ".*"]]
     stacktrace:
       test/list_user_permissions_command_test.exs:79



 10) test long user-defined timeout doesn't interfere with operation (ListUserPermissionsCommandTest)
     test/list_user_permissions_command_test.exs:100
     Assertion with == failed
     code: ListUserPermissionsCommand.list_user_permissions([context[:username]], context[:opts]) == context[:result]
     lhs:  [[vhost: "bunny_testbed", configure: ".*", write: ".*", read: ".*"], [vhost: "/", configure: ".*", write: ".*", read: ".*"]]
     rhs:  [[vhost: "/", configure: ".*", write: ".*", read: ".*"]]
     stacktrace:
       test/list_user_permissions_command_test.exs:101

Command-specific usage displays

Currently, you get the full usage message whenever you use an invalid command string, even if it's a recognized command with the wrong number of arguments. We already define a usage string in each command module; it shouldn't be too hard to create a more targeted usage message for errors generated by the wrong number of arguments.

Specify possible switches in command modules

Option switches for parsing command line arguments are provided in parser module.
Commands can be able to add their own command line options, so they should be added to switches when parsing arguments.

Test suite fails on elixir 1.3.1

running mix test after upgrading to elixir 1.3.1 yields:

.....** (exit) exited in: :gen_server.call(#PID<3.256.0>, {:get_cached_env, 0}, 30000)
    ** (EXIT) no connection to nonode@nohost
    (stdlib) gen_server.erl:212: :gen_server.call/3
    test/list_queues_command_test.exs:49: (module)
    (stdlib) erl_eval.erl:670: :erl_eval.do_apply/6
    (elixir) lib/code.ex:363: Code.require_file/2
    (elixir) lib/kernel/parallel_require.ex:56: anonymous fn/2 in Kernel.ParallelRequire.spawn_requires/5

Add units to rabbitmqctl status

Currently the status command prints all numerical units as-is, with no units associated. We should get some units associated with the output.

NOTE: this may be best accomplished by in-lining transformations to the raw result rather than directly modifying the printing code.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.