https://github.com/robinovitch61/wander
A terminal app/TUI for HashiCorp Nomad
https://github.com/robinovitch61/wander
bubbletea charm charmbracelet hacktoberfest hashicorp hashicorp-nomad nomad terminal tui wish
Last synced: about 1 month ago
JSON representation
A terminal app/TUI for HashiCorp Nomad
- Host: GitHub
- URL: https://github.com/robinovitch61/wander
- Owner: robinovitch61
- License: mit
- Created: 2022-04-13T06:21:28.000Z (over 3 years ago)
- Default Branch: main
- Last Pushed: 2024-06-18T23:55:45.000Z (over 1 year ago)
- Last Synced: 2025-03-31T22:34:25.054Z (8 months ago)
- Topics: bubbletea, charm, charmbracelet, hacktoberfest, hashicorp, hashicorp-nomad, nomad, terminal, tui, wish
- Language: Go
- Homepage:
- Size: 62.8 MB
- Stars: 459
- Watchers: 7
- Forks: 16
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-nomad - robinovitch61/wander - A terminal UI for Nomad. (User interfaces)
- awesome-tuis - wander
- awesome-cli-apps-in-a-csv - wander - HashiCorp Nomad terminal client. (<a name="system"></a>System tools)
- awesome-nomad - robinovitch61/wander - Wander is a terminal-based TUI application for efficiently managing and monitoring HashiCorp Nomad clusters with features like live log tailing, event monitoring, and administrative controls. (Infrastructure setup / User Interfaces and Dashboards)
- charm-in-the-wild - wander - A HashiCorp Nomad terminal client. (_built with Bubble Tea_) (Applications / Cloud and DevOps)
README
# wander
An efficient terminal application/TUI for interacting with your [HashiCorp Nomad](https://www.nomadproject.io/) cluster.
- Browse jobs, allocations, and tasks
- Live tail logs
- Tail global or targeted events
- Exec to interact with running tasks
- Administrative actions (e.g. restart tasks)
- View resource usage stats (memory, CPU)
- See full job or allocation specs
- Save any content to a local file
`wander` is written with tools from [Charm](https://charm.sh/).
[Feature requests and bug reports are welcome](https://github.com/robinovitch61/wander/issues/new/choose).
## Demo

[Screenshots](./img/screenshots#readme)
## Flow Diagram

## Installation
The following options are available depending on your platform and tooling:
```shell
# homebrew
brew install robinovitch61/tap/wander
# upgrade using homebrew
brew update && brew upgrade wander
# nix-shell
# ensure NUR is accessible (https://github.com/nix-community/NUR)
nix-shell -p nur.repos.robinovitch61.wander
# nix flakes
# ensure flake support is enabled (https://nixos.wiki/wiki/Flakes#Enable_flakes_temporarily)
nix run github:robinovitch61/nur-packages#wander
# arch linux
# PKGBUILD available at https://aur.archlinux.org/packages/wander
yay -S wander-bin
# with go (https://go.dev/doc/install)
go install github.com/robinovitch61/wander@latest
# windows with winget
winget install robinovitch61.wander
# windows with scoop
scoop bucket add robinovitch61 https://github.com/robinovitch61/scoop-bucket
scoop install wander
# windows with chocolatey
choco install wander
```
You can also download [prebuilt releases](https://github.com/robinovitch61/wander/releases) and move the unpacked
executable to somewhere in your `PATH`, e.g. `/usr/local/bin`.
## Usage
Run the app by running `wander` in a terminal. See `wander --help` and config section below for details.
## Configuration
`wander` can be configured in three ways:
1. Command line arguments, visible by running `wander --help`.
2. Environment variables. These map to the configuration file below (e.g. `nomad_addr` in yaml is the `NOMAD_ADDR`
environment variable).
3. A yaml config file at `$HOME/.wander.yaml`, or a custom config file path passed to the `--config` argument. Complete
example below.
Priority in order of highest to lowest is command line arguments, then environment variables, then the config file.
Example yaml file showing all options (copy this into `$HOME/.wander.yaml` and uncomment/edit as desired):
```yaml
# Nomad address. Default "http://localhost:4646"
#nomad_addr: "http://localhost:4646"
# Nomad token
#nomad_token: ""
# Nomad region
#nomad_region: ""
# Nomad namespace. Default "*"
#nomad_namespace: "*"
# Nomad http auth, in the form of "user" or "user:pass"
#nomad_http_auth: ""
# Path to a PEM encoded CA cert file to use to verify the Nomad server SSL certificate
#nomad_cacert: ""
# Path to a directory of PEM encoded CA cert files to verify the Nomad server SSL certificate. If both cacert and capath are specified, cacert is used
#nomad_capath: ""
# Path to a PEM encoded client cert for TLS authentication to the Nomad server. Must also specify client key
#nomad_client_cert: ""
# Path to an unencrypted PEM encoded private key matching the client cert
#nomad_client_key: ""
# The server name to use as the SNI host when connecting via TLS
#nomad_tls_server_name: ""
# If True, do not verify TLS certificates. Default False
#nomad_skip_verify: False
# Seconds between updates for job & allocation pages. Disable with -1. Default 2
#wander_update_seconds: 2
# Columns to display for Jobs view - can reference Meta keys. Default "Job,Type,Namespace,Status,Count,Submitted,Since Submit"
#wander_job_columns: "Job,Type,Namespace,Status,Count,Submitted,Since Submit"
# Columns to display for Tasks for Job view. Default "Node ID,Alloc ID,Task Group,Alloc Name,Task Name,State,Started,Finished,Uptime"
#wander_tasks_for_job_columns: "Node ID,Alloc ID,Task Group,Alloc Name,Task Name,State,Started,Finished,Uptime"
# Columns to display for All Tasks view. Default "Job,Node ID,Alloc ID,Task Group,Alloc Name,Task Name,State,Started,Finished,Uptime"
#wander_all_tasks_columns: "Job,Node ID,Alloc ID,Task Group,Alloc Name,Task Name,State,Started,Finished,Uptime"
# If True, start with compact header. Default False
#wander_compact_header: False
# If True, start in All Tasks view. Default False
#wander_start_all_tasks: False
# If True, remove unnecessary gaps between table columns when possible. Default True
# If you want column positions to remain static as you scroll and filter, set this to False
#wander_compact_tables: True
# Log byte offset from which logs start. Default 1000000
#wander_log_offset: 1000000
# If True, start with filtering active on first view. Default False
#wander_start_filtering: False
# If True, filtering highlights and allows cycling through matches, but does not remove surrounding context. Default True
#wander_filter_with_context: True
# If True, follow new logs as they come in rather than having to reload. Default True
#wander_log_tail: True
# If True, copy the full path to file after save. Default False
#wander_copy_save_path: False
# Topics to follow in event streams, comma-separated. Default "Job,Allocation,Deployment,Evaluation"
# see https://www.nomadproject.io/api-docs/events#event-stream
#wander_event_topics: "Job,Allocation,Deployment,Evaluation"
# Namespace used in stream for all events. "*" for all namespaces. Default "default"
#wander_event_namespace: "default"
# The jq (https://stedolan.github.io/jq/) query used for parsing general events. "." to show entire event JSON. Default is:
# .Events[] | {
# "1:Index": .Index,
# "2:Topic": .Topic,
# "3:Type": .Type,
# "4:Name": .Payload | (.Job // .Allocation // .Deployment // .Evaluation) | (.JobID // .ID),
# "5:ID": .Payload | (.Job.ID // (.Allocation // .Deployment // .Evaluation).ID[:8])
# }
# The numbering exists to preserve ordering, as https://github.com/itchyny/gojq does not keep the order of object keys
#wander_event_jq_query: >
# .Events[] | {
# "1:Index": .Index,
# "2:Topic": .Topic,
# "3:Type": .Type,
# "4:Name": .Payload | (.Job // .Allocation // .Deployment // .Evaluation) | (.JobID // .ID),
# "5:ID": .Payload | (.Job.ID // (.Allocation // .Deployment // .Evaluation).ID[:8])
# }
# The jq (https://stedolan.github.io/jq/) query used for parsing allocation-specific events. "." to show entire event JSON. Default is:
# .Index as $index | .Events[] | .Type as $type | .Payload.Allocation |
# .DeploymentStatus.Healthy as $healthy | .ClientStatus as $clientStatus | .Name as $allocName |
# (.TaskStates // {"":{"Events": [{}]}}) | to_entries[] | .key as $k | .value.Events[] | {
# "0:Index": $index,
# "1:AllocName": $allocName,
# "2:TaskName": $k,
# "3:Type": $type,
# "4:Time": ((.Time // 0) / 1000000000 | todate),
# "5:Msg": .DisplayMessage,
# "6:Healthy": $healthy,
# "7:ClientStatus": $clientStatus
# }
# The numbering exists to preserve ordering, as https://github.com/itchyny/gojq does not keep the order of object keys
#wander_alloc_event_jq_query: >
# .Index as $index | .Events[] | .Type as $type | .Payload.Allocation |
# .DeploymentStatus.Healthy as $healthy | .ClientStatus as $clientStatus | .Name as $allocName |
# (.TaskStates // {"":{"Events": [{}]}}) | to_entries[] | .key as $k | .value.Events[] | {
# "0:Index": $index,
# "1:AllocName": $allocName,
# "2:TaskName": $k,
# "3:Type": $type,
# "4:Time": ((.Time // 0) / 1000000000 | todate),
# "5:Msg": .DisplayMessage,
# "6:Healthy": $healthy,
# "7:ClientStatus": $clientStatus
# }
# For `wander serve`. Hostname of the machine hosting the ssh server. Default "localhost"
#wander_host: "localhost"
# For `wander serve`. Port for the ssh server. Default 21324
#wander_port: 21324
# For `wander serve`. Host key path for wander ssh server
#wander_host_key_path: ""
# For `wander serve`. Host key PEM block for wander ssh server
#wander_host_key_pem: ""
# Custom colors
#wander_logo_color: "#DBBD70"
```
## Exec Command
`wander` ships with an `exec` command similar to the [`nomad alloc exec`](https://developer.hashicorp.com/nomad/docs/commands/alloc/exec)
utility. Example usage:
```shell
# specify job and task, assuming single allocation
wander exec alright_stop --task redis echo "hi"
# specify allocation, assuming single task
wander exec 3dca0982 echo "hi"
# use prefixes of jobs or allocation ids
wander exec al echo "hi" # prefix of job "alright_stop"
wander exec 3d echo "hi" # prefix of alloc ID "3dca0982"
# specify flags for the exec command with --
wander exec alright_stop --task redis -- echo -n "hi"
```
## SSH App
`wander` can be served via ssh application. For example, you could host an internal ssh application for your company
such that anyone on the internal network can `ssh -p ` and immediately access `wander` without
installing or configuring anything.
Optionally, users can pass in their own nomad token with `ssh -p -t `. The `-t` argument does not
stand for token - it forces `ssh` to allocate a pty.
Serve the ssh app with `wander serve`.
## Trying It Out
You can try `wander` out by running a local development nomad cluster following [these instructions](https://learn.hashicorp.com/tutorials/nomad/get-started-run?in=nomad/get-started):
```sh
# in first terminal session, start and leave nomad running in dev mode
sudo nomad agent -dev -bind 0.0.0.0 -log-level INFO
# in a different terminal session, create example job and run it
nomad job init
nomad job run example.nomad
# run wander
wander
```
## Manually Specifying the `wander` Version
`wander` uses [carlmjohnson/versioninfo](https://blog.carlmjohnson.net/post/2023/golang-git-hash-how-to/) to expose
version/revision info. If the environment in which you're installing wander does not allow for git repos, prebuilt
binaries, or `go install`, then you can manually specify the output of `wander --version` at build time as follows:
```sh
go build -ldflags "-X github.com/robinovitch61/wander/cmd.Version=vX.Y.Z"
```
In this case, you're responsible for ensuring the specified version is in sync with what is actually being built.
## Development
To manually build:
```shell
git clone git@github.com:robinovitch61/wander.git
cd wander
go build # outputs ./wander executable
```
The [scripts](/scripts) directory contains various development helper scripts.
If the `WANDER_DEBUG` environment variable is set to `true`, the `dev.Debug(s string)` function outputs to `WANDER_DEBUG_PATH` (defaults to `wander.log`).