Open-Source Wikis

/

Consul

/

Apps

/

CLI

hashicorp/consul

CLI

The consul CLI is the operator interface to a running cluster. It is built on github.com/mitchellh/cli and lives entirely under command/. The binary's main.go is just a thin entrypoint:

// main.go
cmds := command.RegisteredCommands(ui)
cli := &mcli.CLI{Args: os.Args[1:], Commands: cmds, ...}
exitCode, err := cli.Run()

command.RegisteredCommands (in command/registry.go) returns a map[string]mcli.CommandFactory — a flat map keyed by command path with values that lazily construct each subcommand. The Mitchell CLI library handles parsing, autocompletion, and help generation from that map.

Directory layout

command/
├── registry.go            # The big map of (key → factory) entries
├── cli/                   # Shared CLI plumbing (BasicUI, etc.)
├── flags/                 # Common flag definitions (HTTP, DNS, ACL token, ...)
├── helpers/               # Output formatting, error rendering
├── agent/                 # `consul agent`
├── acl/                   # `consul acl ...` (token, policy, role, auth-method, binding-rule, templated-policy)
├── catalog/               # `consul catalog ...`
├── config/                # `consul config ...` (config entries)
├── connect/               # `consul connect ...` (CA, envoy, proxy, expose, redirect-traffic)
├── debug/                 # `consul debug`
├── event/                 # `consul event`
├── exec/                  # `consul exec`
├── intention/             # `consul intention ...` (legacy intentions tooling)
├── kv/                    # `consul kv put|get|delete|export|import`
├── lock/                  # `consul lock`
├── members/               # `consul members`
├── monitor/               # `consul monitor` (live log tail)
├── operator/              # `consul operator ...` (autopilot, raft, usage, utilization, area)
├── peering/               # `consul peering ...`
├── resource/              # `consul resource ...` (v2 resource API)
├── services/              # `consul services ...`
├── snapshot/              # `consul snapshot ...` (save/restore/inspect/decode)
├── tls/                   # `consul tls ca|cert ...` helper for cert generation
├── troubleshoot/          # `consul troubleshoot ...` mesh diagnostics
├── validate/              # `consul validate` config validator
├── watch/                 # `consul watch`
├── join/, leave/, forceleave/, info/, login/, logout/, keygen/, keyring/, maint/, reload/, rtt/, version/
└── ...

Subcommand surface (193 packages)

The full surface is most easily explored by reading command/registry.go. A flavor:

Top-level Selected sub-commands
agent The long-running daemon
acl bootstrap, policy, role, token, auth-method, binding-rule, templated-policy, set-agent-token
catalog datacenters, nodes, services
config read, write, list, delete
connect ca get/set, envoy (bootstrap helper), proxy, expose, redirect-traffic
intention create, delete, get, list, match, check (legacy compatibility)
kv put, get, delete, export, import
members List Serf members for LAN/WAN/segment
operator autopilot get/set/state, raft list-peers/remove-peer/transfer-leader, usage, utilization
peering generate, establish, list, read, delete, exported-services
resource read, list, apply, delete (and *-grpc variants for the gRPC API)
services register, deregister, export, exported-services, imported-services
snapshot save, restore, inspect, decode
tls ca create, cert create
troubleshoot proxy, upstreams, ports
debug, event, exec, info, join, leave, force-leave, keygen, keyring, lock, login, logout, maint, monitor, reload, rtt, validate, version, watch one command each

Anatomy of a subcommand

Every subcommand package follows the same shape:

// command/<name>/<name>.go
type cmd struct {
    UI    cli.Ui
    flags *flag.FlagSet
    http  *flags.HTTPFlags
    help  string
}

func New(ui cli.Ui) cli.Command {
    c := &cmd{UI: ui}
    c.init()
    return c
}

func (c *cmd) init() {
    c.flags = flag.NewFlagSet("", flag.ContinueOnError)
    c.http = &flags.HTTPFlags{}
    flags.Merge(c.flags, c.http.ClientFlags())
    c.help = flags.Usage(helpText, c.flags)
}

func (c *cmd) Run(args []string) int {
    if err := c.flags.Parse(args); err != nil { return 1 }
    client, err := c.http.APIClient()
    // ... call api.Client methods, render result with c.UI ...
}

func (c *cmd) Synopsis() string { return synopsis }
func (c *cmd) Help() string     { return c.help }

Almost every subcommand goes through the public api package (api/) to talk to a running agent. That keeps the CLI thin and ensures public Go users have access to everything the CLI does.

Shared flag plumbing

command/flags/ defines:

  • HTTPFlags-http-addr, -token, -token-file, -ca-file, TLS options
  • ServerFlags-datacenter, -namespace, -partition
  • EnvoyFlags, LogFlags, UsageFlags, ...

Subcommands compose these with flags.Merge. The HTTP flags land in api.Config via HTTPFlags.APIClient(), ensuring uniform behavior across commands.

Output formatting

command/helpers/ and per-command helpers.go files contain table renderers, JSON pretty-printers, and the colored output used by consul members and consul operator raft list-peers. The base cli.BasicUI (in command/cli/) wraps Mitchell's mcli.BasicUi and adds color support keyed off of the -no-color flag.

Special cases

  • consul agent is the only subcommand that doesn't talk to an existing agent — it is the agent (command/agent/agent.go calls agent.New(...) and runs the long-lived process).
  • consul resource ... -grpc subcommands talk to the v2 resource service over gRPC instead of HTTP.
  • consul connect envoy generates an Envoy bootstrap config and execs envoy directly. Code in command/connect/envoy/.
  • consul connect proxy is the legacy in-tree built-in proxy (now mostly superseded by Envoy/dataplane).
  • consul lock runs an arbitrary user command while holding a Consul session-based lock; useful for leader election in scripts.

Entry points for modification

  • To add a new top-level command: create command/<name>/<name>.go with New(ui) and add an entry{"<name>", func(...) ...} line to command/registry.go.
  • To add a sub-command (e.g., consul foo bar): create command/foo/bar/bar.go and add the corresponding entry{"foo bar", ...} line.
  • To add a new shared flag: extend command/flags/. The HTTP flags are the most commonly extended.
  • To customize output across commands: extend command/helpers/ rather than per-command files.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

CLI – Consul wiki | Factory