Giter VIP home page Giter VIP logo

wander's Introduction

wander

Latest Release GoDoc Build Status

An efficient terminal application/TUI for interacting with your HashiCorp Nomad 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.

Feature requests and bug reports are welcome.

Demo

Screenshots

Flow Diagram

Installation

The following options are available depending on your platform and tooling:

# 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 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):

# 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 utility. Example usage:

# 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 <your-port> <your-host> and immediately access wander without installing or configuring anything.

Optionally, users can pass in their own nomad token with ssh -p <port> <host> -t <token>. 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:

# 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 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:

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:

git clone [email protected]:robinovitch61/wander.git
cd wander
go build  # outputs ./wander executable

The 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).

wander's People

Contributors

beakman avatar cshintov avatar dbalan avatar moyiz avatar neomantra avatar robinovitch61 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

wander's Issues

Ability to exec on an allocation

Will require a websocket impl to https://www.nomadproject.io/api-docs/allocations#exec-allocation

Trigger should be pressing s while selecting a task on the allocations page.

Unsure of the UI yet. Could make a terminal component that uses a textinput at the bottom. Unsure if that will handle multiline commands (suffixed with \) nicely out of the box, or if we just shouldn't support that right away. Should look and feel as much as possible like a normal terminal, with the ability to save sessions to local files just like viewports can.

Unable to run with an empty nomad auth token

Describe the bug
The readme states that -t "" should work to send an empty auth token but I receive an error

To Reproduce

$ wander -a $NOMAD_ADDR -t ""
error: set WANDER_TOKEN env variable, wander_token in config file, or --token argument

$ wander               
Using config file: /Users/james/.wander.yaml
error: set WANDER_TOKEN env variable, wander_token in config file, or --token argument

Expected behavior
The -t should be optional or work with an empty string

Desktop (please complete the following information):

  • OS: macos
  • Version: 0.3.0

Feature request: Full Screen mode / Hide headers / headless mode

Is your feature request related to a problem? Please describe.

When I split my terminal horizontally, I would like to hide the headers (showing shortcuts and cluster information) because I have not so much space for this information frame.

Describe the solution you'd like

I would like a shortcut allowing to toggle the headers area on and off to maximize the table height.

To me, the only information being important at all time in the header is the context, so it may be a good idea to keep it in "full screen mode".

Describe alternatives you've considered

Other (harder) alternative should be a ctrl + and ctrl - to increase/decrease the area and adjust it ( please note there are always 3 empty lines above the title of the table)

I have no workaround for now and I deal with it by putting the terminals on a bigger screen or by lowering down the char size...

Additional context

Similar to derailed/k9s#270

If unclear I'll provide more context

Off topic : Great Work for this wonderful app ๐Ÿ‘ ๐Ÿ‘

Saving viewport contents should not include wrapping newlines if wrap is on

Describe the bug
Saving viewport contents when visual wrapping is on includes newlines in the saved content. It should not include wrapping newlines.

To reproduce
In a viewport with wrapping on and long enough lines to wrap around, save the contents with ctrl + s. You'll see the newlines are saved as well.

Expected behavior
Newlines for visual wrapping purposes should not be present in the saved content.

Edit the job specs and restart a deployment

Describe the solution you'd like
Currently we can view a job spec by typing p in wander.

That would be great if we can edit the specs and plan a new allocation like in the ui.

By the way, thanks for this amazing tool

Goreleaser support for releases and homebrew

Goreleaser is a really great tool for releasing Go projects. I also note its author works at Charm.

By adopting a .goreleaser.yml file and a GitHub action, the wander project could be automatically built every push... and upon semantic version tags like v0.1.1, a GitHub Release and a Homebrew tap can easily be supported. There are other release targets like Debian packages, but homebrew is pretty great for CLI tools.

I committed a branch to my wander fork which does the above. However some aspects are hard-coded to my neomantra GitHub account, so I have not made a PR yet.

Links to the main blobs:

You can see the branch build and tag builds here:
https://github.com/neomantra/wander/actions

I tagged a v0.0.1... you can see the resultant release, with auto-Changelog here:
https://github.com/neomantra/wander/releases

And you can see my homebrew tap was updated here:
neomantra/homebrew-github@413bed1

You can do the following to install:

brew tap neomantra/homebrew-github
brew install wander

Doing Homebrew support requires a Homebrew repo.... if you don't want to support that we can remove it. You must set the secret HOMEBREW_TAP_GITHUB_TOKEN on your wander repo; it is an access token which can affect that Homebrew repo.

Let me know if you have questions...

v1/:job_id/allocations requires namespace

Listing allocations of a job in a namespace doesn't work. No results are returned. At the Nomad HTTP API level, one must provide the namespace with /v1/:job_id/allocations. I also tried the wildcard * namespace and it did not work. Long story short, the job namespace needs to be added to HTTP request.

I have a PR forthcoming.

Better error messages

Especially the "invalid token" message is bizarre and leaves no recourse other than quitting.

Ability to tail logs without refresh

I'm thinking that while on the logs page, the keyhelp that shows up at the top of the page shows f tail logs

Once f is pressed, a tailing indicator shows up to the right of the filter. Pressing f again turns it off.

Log offsets will need to be tracked, and we'll need to stop using the "plain": "true", param in the current FetchLogs impl. There will probably need to be another nomad helper function that returns a suitable stream data structure rather than the full buffer read that currently occurs with nomad.Get

Watching logs results in nil pointer exception

Describe the bug

Watching logs of an allocation using follow is causing a nil pointer exception.

panic: runtime error: invalid memory address or nil pointer dereference                                                                                                                       
[signal SIGSEGV: segmentation violation code=0x1 addr=0x8 pc=0x95195c]

goroutine 785 [running]:
github.com/robinovitch61/wander/internal/tui/nomad.ReadLogsStreamNextMessage.func1()
	/home/ghthor/go/pkg/mod/github.com/robinovitch61/[email protected]/internal/tui/nomad/logs.go:106 +0x3c
github.com/charmbracelet/bubbletea.(*Program).StartReturningModel.func6.1()
	/home/ghthor/go/pkg/mod/github.com/charmbracelet/[email protected]/tea.go:470 +0x33
created by github.com/charmbracelet/bubbletea.(*Program).StartReturningModel.func6
	/home/ghthor/go/pkg/mod/github.com/charmbracelet/[email protected]/tea.go:468 +0x14d
exit status 2

To reproduce
Steps to reproduce the behavior:

  1. Follow the logs of an allocation
  2. Perform a deployment that will cause that allocation to be stopped
  3. See error

I believe this is the reproduction, but I haven't confirmed as yet. I've seen it twice now, but I was iterating on something else and didn't go intentionally reproduce.

Expected behavior
Return to the allocations page?
OR Post to the logs that the allocation has been stopped maybe?

Screenshots

Screenshot_2023-02-14_00-49-37

Please complete the following information:

  • OS: linux
  • Terminal: xfce4-terminal
  • Version: 0.9 built from source
  • Configuration options: none

Additional context
Add any other context about the problem here.

Customizable event log format

The event log is a big piece of json, hard to read.
I'm wishing we can provide a jq query in config file and use that to transform the event log into information the user cares about.

Thanks for the great tool btw!

Option to "exec shell" in the allocation view

As a wander user, I want an option to enter a bash shell on a running job/allocation from the logs view.

Screen Shot 2022-05-26 at 1 41 45 PM

Ideally, there should be an additional option added to the list at the top of this page that opens a shell. This is basically re-implementing the "Exec" feature of the on nomad's /ui/jobs endpoint.

Refactor pages into page component

There's a lot of duplicate logic in pages that can be consolidated into a single page component. I think this will be possible. Some state may have to move up to main.

Allocation-specific event streams

From @chuckyz in #60:

Something that would also be useful -- if it's not too much work -- is the event stream on a single alloc. Sometimes you get an alloc that just gets hella cranky and being able to go 'alright, what are you, and only you doing.' I'd imagine that'd be e on a single alloc from within a job view.

I do the curl thing a lot sometimes. We actually run a python script which tails the global event stream from all namespaces and dumps it into Loki, but it's a lot of events and sometimes having a real-time stream at your fingertips is just what you need.

Ability to inspect job spec

Should be fairly straightforward - additional http endpoint and page implementation. Pressing d (describe? open to other options) when a job (allocation?) is selected shows the spec page. Escape while viewing a spec returns to the job (allocation?) page. Viewport shows nicely formatted spec in cursor-disabled viewport, similar to logline page today for a json log.

Consider using NOMAD_ config prefixes instead of WANDER_ config prefixes to match nomad cli

Inspired by comment on https://lobste.rs/s/b67kmz/wander_terminal_app_tui_for_hashicorp

Why the choice to use different variables than the nomad cli tool itself?

At one point I had conflicts between them when wanting to point at a different cluster, so I decided to make an explicit config set specifically for wander. I can see how it might be a bit annoying given that 90% of users will have the same values for NOMAD_ADDR/WANDER_ADDR and NOMAD_TOKEN/WANDER_TOKEN.

I may want to change this in a backwards-compatible way so NOMAD_ prefixes are the recommended way. Maybe print a warning that the config names have changed and will be phased out in a later release.

Alternatively, maybe WANDER_ prefixes are better as they're explicitly for wander only and there will never be confusion with the CLI.

Add visual mode to viewport for selecting and copying text

I think this is doable, particularly starting with a full-line selection.

Initial impl:

  • in any viewport-showing page, hit V to enter visual mode
  • while in visual mode, cursor is visible (even if disabled) but a different color
  • when moving cursor up and down, selected portion is sticky (i.e. V then k k k j leaves 3 full lines selected). Selected lines show up slightly different color than the cursor line, both colors are different from normal cursor color
  • on escape, exit visual mode without copying selected lines to clipboard
  • on enter, copy selected lines to clipboard and exit visual mode
  • left/right don't do anything (yet) while in visual mode, and no vim-like bindings (no viw, etc.), just up and down full line selection to start
  • if line is copied but overflows viewport, the entire line is copied (including the parts not shown)

Show meta data for a job

The nomad UI has a "Meta" section showing optional metadata. Might be useful to see this depending on if people add useful data there in there cluster.

Ability to save any viewport as a local file

This should be implemented on the viewport component so any viewport can be saved

Won't handle windows paths out of the box yet

$CURRENT_PAGE = jobs/allocations/logs/log
$TIMESTAMP = ISO 8601 time up to seconds

Placeholder textinput reads "Output file name for $CURRENT_PAGE (path optional)"

On confirm save:

  • if filepath empty, will use default of "./$TIMESTAMP_$CURRENT_PAGE.txt"
  • if just a file name, will use "./$FILE_NAME.txt"
  • if just a path with no file name, will use default of "$PATH/$TIMESTAMP_$CURRENT_PAGE.txt"
  • if there is a conflicting file of the same name in the target directory, will append current "_$TIMESTAMP" before .txt (theoretically, if user saves the same file twice within 1s, it will be overwritten, and that's fine
  • anything with ~, ., ..in the specified path will be resolved to its full path and conflicting file logic applied

After successful save, textinput will be replaced with "$FULL_PATH_INCLUDING_FILENAME saved!" for 5s

Maybe add a "COPY_FILEPATH_AFTER_SAVE" config option?

If errors, should return ErrMsg and be handled by main as usual

Poll for updates

Probably don't do it on logs page, but other (re)loadable pages are probably fine to poll for updates every ~2-3s or something

Better logo

I (Leo) am not a great designer. A better logo than two yellow triangles posing as sand dunes would be much appreciated :)

Running a long-running script using the exec function appears to timeout

Describe the bug
When running a long-running script in a nomad container via the wander exec feature, the session timed out twice in a row with the below message. Unfortunately I can't be sure how long the timeout took to happen, but it was roughly no more than 10min.

To reproduce
Steps to reproduce the behavior:

  1. Exec into a container
  2. Run a long running script (mine was a python script)
  3. Observe this message popping up after a few minutes:
Error: websocket: close sent

if this seems wrong, consider opening an issue here: https://github.com/robinovitch61/wander/issues/new/choose

q/ctrl+c to quit

Expected behavior
Connection should stay open until I choose to exit. FWIW this script was regularly printing logs to stdout every 20s or so. I can't find a truly reproducible case but will keep an eye out!

Please complete the following information:

  • OS: MacOS Ventura 13.0
  • Terminal: zsh
  • Version: v0.9.0
  • Configuration options used, e.g. cli arguments, env vars, and/or .wander.yaml file: None

Preserve cursor position after removing filter

It's annoying how you can search, find something, then want to view that in context but when you remove the filter the cursor/screen isn't showing what you searched for. Happens most often for me viewing a spec or event.

Will be tricky on things that aren't selectable...

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.