- **Shortcuts**: Add hostname normalization with domain stripping and hyphen folding. Include alias generation for cached hosts. - **Shell Hook**: Automate 24h cache refresh trigger with shell startup hook. Add install/uninstall commands for bash, zsh, and fish. - **Wizard**: Extend setup wizard to configure shortcuts (domains, hyphen stripping) and default SSH port. - **Cache**: Add `GetByShortcut` for resolving hosts via normalized shortcuts. Implement `NeedsRefresh` / `SetRefreshed` logic for refresh timestamps. - **Tests**: Comprehensive unit tests for shortcuts, hook installation, cache refresh, and alias generation. - **Docs**: Update README with shortcuts, shell hook, and default SSH port configuration.
This commit is contained in:
@@ -27,6 +27,10 @@ netssh -p 2222 admin@app-server-03 uptime
|
||||
- **Setup wizard** — interactive first-run onboarding; re-run anytime with `netssh configure`
|
||||
- **Shell completion** — install without sudo via `netssh completion install`
|
||||
- **Default SSH user** — set a fallback username once in config instead of typing it every time
|
||||
- **Default SSH port** — set a fallback port in config; injected as `-p` when not specified on the command line
|
||||
- **Host shortcuts** — type `web01` instead of `web01.example.com`; configurable domain strip and hyphen folding
|
||||
- **Shell aliases** — `netssh alias` generates shell aliases for all cached hosts
|
||||
- **Automatic 24h cache refresh** — the cache is refreshed in the background every 24 hours
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -94,6 +98,12 @@ cache:
|
||||
|
||||
ssh:
|
||||
default_user: admin # used when no user is specified on the command line
|
||||
default_port: 2222 # optional; injected as -p if not specified on the command line
|
||||
|
||||
shortcuts:
|
||||
domains: # strip these suffixes to create short aliases
|
||||
- .example.com
|
||||
strip_hyphens: false # if true, fsn1-web01 → fsn1web01 (cache-only resolution)
|
||||
```
|
||||
|
||||
Any value can be overridden with environment variables (`NETSSH_NETBOX_URL`, `NETSSH_NETBOX_TOKEN`, etc.).
|
||||
@@ -139,6 +149,76 @@ netssh root@my-router # user@ prefix wins → ssh root@10.0.0.1
|
||||
netssh -l ops my-router # -l flag wins → ssh -l ops 10.0.0.1
|
||||
```
|
||||
|
||||
### Default SSH port
|
||||
|
||||
Set `ssh.default_port` in the config to use a non-standard port without specifying it every time:
|
||||
|
||||
```sh
|
||||
netssh my-router # → ssh -p 2222 -l admin 10.0.0.1
|
||||
```
|
||||
|
||||
The default is only applied when `-p` is not already present in the SSH arguments. An explicit `-p` always takes precedence:
|
||||
|
||||
```sh
|
||||
netssh -p 22 my-router # -p flag wins → ssh -p 22 10.0.0.1
|
||||
```
|
||||
|
||||
### Host shortcuts
|
||||
|
||||
Configure short aliases so you can type `web01` instead of `web01.example.com`:
|
||||
|
||||
```yaml
|
||||
shortcuts:
|
||||
domains:
|
||||
- .example.com
|
||||
- .example.de
|
||||
strip_hyphens: false # optional
|
||||
```
|
||||
|
||||
Resolution order:
|
||||
|
||||
1. **Exact match** — the input is looked up as-is in the cache.
|
||||
2. **Domain expansion** — if the input contains no dot, each configured domain is appended and tried (`web01` → `web01.example.com`). If no cache hit, NetBox is queried with the expanded name.
|
||||
3. **Hyphen folding** (`strip_hyphens: true`) — hyphens are inserted back before looking up in the cache (`fsn1web01` → `fsn1-web01.example.com`). This only works when the host is already cached; run `netssh cache refresh` first.
|
||||
|
||||
| Input | Config | Resolved as |
|
||||
|-------|--------|-------------|
|
||||
| `web01` | `domains: [.example.com]` | `web01.example.com` |
|
||||
| `fsn1web01` | `domains: [.example.com]`, `strip_hyphens: true` | `fsn1-web01.example.com` (cache only) |
|
||||
|
||||
### Shell aliases
|
||||
|
||||
Generate shell aliases for all cached hosts based on the shortcut settings:
|
||||
|
||||
```sh
|
||||
netssh alias # bash/zsh syntax
|
||||
netssh alias --shell fish # fish syntax
|
||||
```
|
||||
|
||||
Example output:
|
||||
|
||||
```bash
|
||||
# netssh aliases (3 hosts) — source with: eval "$(netssh alias)"
|
||||
alias db01='netssh db01.example.com'
|
||||
alias fsn1web01='netssh fsn1-web01.example.com'
|
||||
alias web01='netssh web01.example.com'
|
||||
```
|
||||
|
||||
Add to your shell startup file:
|
||||
|
||||
```sh
|
||||
# bash / zsh — in ~/.bashrc or ~/.zshrc
|
||||
eval "$(netssh alias)"
|
||||
|
||||
# fish — in ~/.config/fish/config.fish
|
||||
netssh alias --shell fish | source
|
||||
|
||||
# scripts
|
||||
source <(netssh alias)
|
||||
```
|
||||
|
||||
Without a `shortcuts` config, the alias name is derived from the full hostname with dots replaced by underscores (e.g. `web01_example_com`). If two hosts would produce the same alias name, the first entry wins and a warning is printed to stderr.
|
||||
|
||||
### Interactive TUI
|
||||
|
||||
Run without arguments to open the interactive search:
|
||||
@@ -186,6 +266,25 @@ netssh cache refresh --tag prod --kind vm # combine filters
|
||||
netssh cache clear # wipe the cache
|
||||
```
|
||||
|
||||
The cache is refreshed automatically in the background every 24 hours. The trigger fires on the next SSH connect or TUI start after the interval has elapsed — there is no delay to the connection itself. The timestamp of the last refresh is stored in `~/.cache/netssh/last_refresh`.
|
||||
|
||||
To also trigger the check at shell startup (before you run any SSH command), install the shell hook:
|
||||
|
||||
```sh
|
||||
netssh hook install # auto-detects $SHELL
|
||||
netssh hook install --shell bash
|
||||
netssh hook install --shell zsh
|
||||
netssh hook install --shell fish
|
||||
```
|
||||
|
||||
This appends a single line (`netssh shell-init`) to your shell profile. To remove it:
|
||||
|
||||
```sh
|
||||
netssh hook uninstall
|
||||
```
|
||||
|
||||
The hook is a no-op when the cache is fresh — it adds no measurable delay to your shell startup.
|
||||
|
||||
### Search (for scripting)
|
||||
|
||||
```sh
|
||||
@@ -228,6 +327,59 @@ autoload -Uz compinit && compinit
|
||||
|
||||
Completions are served from the local cache — no network request on every `<Tab>`.
|
||||
|
||||
## Shell Hook
|
||||
|
||||
The shell hook runs `netssh shell-init` at the start of every new shell session. It checks whether the cache is older than 24 hours and, if so, starts a background refresh. The check reads a single small file and adds no measurable delay to your shell startup.
|
||||
|
||||
### Install
|
||||
|
||||
```sh
|
||||
netssh hook install # auto-detects $SHELL
|
||||
netssh hook install --shell bash
|
||||
netssh hook install --shell zsh
|
||||
netssh hook install --shell fish
|
||||
```
|
||||
|
||||
This appends exactly one line to your shell profile:
|
||||
|
||||
```sh
|
||||
netssh shell-init # netssh cache auto-refresh
|
||||
```
|
||||
|
||||
| Shell | Profile file |
|
||||
|-------|-------------|
|
||||
| bash | `~/.bashrc` |
|
||||
| zsh | `~/.zshrc` |
|
||||
| fish | `~/.config/fish/config.fish` |
|
||||
|
||||
The install is idempotent — running it again does nothing if the hook is already present.
|
||||
|
||||
Reload your profile after installation:
|
||||
|
||||
```sh
|
||||
source ~/.bashrc # bash
|
||||
source ~/.zshrc # zsh
|
||||
source ~/.config/fish/config.fish # fish
|
||||
```
|
||||
|
||||
### Uninstall
|
||||
|
||||
```sh
|
||||
netssh hook uninstall # auto-detects $SHELL
|
||||
netssh hook uninstall --shell zsh
|
||||
```
|
||||
|
||||
Removes the `netssh shell-init` line from the profile and collapses any blank lines left behind.
|
||||
|
||||
### How it differs from the connect-time trigger
|
||||
|
||||
| Trigger | When it fires |
|
||||
|---------|--------------|
|
||||
| Connect / TUI start | On the next SSH command or `netssh` TUI after 24 h |
|
||||
| Shell hook | On the first new shell session after 24 h |
|
||||
|
||||
Both triggers are non-blocking: the refresh runs in the background and your SSH connection (or prompt) is not delayed. You can install both — they share the same `~/.cache/netssh/last_refresh` timestamp, so the background process runs at most once per 24 hours regardless of how many shells or connections you open.
|
||||
|
||||
## Development
|
||||
|
||||
```sh
|
||||
@@ -235,7 +387,7 @@ go test ./... # run all tests
|
||||
go build ./... # build all packages
|
||||
```
|
||||
|
||||
The test suite covers the cache, NetBox client (via `httptest`), IP resolver chain, SSH argument parser, config loading, and the setup wizard.
|
||||
The test suite covers the cache, NetBox client (via `httptest`), IP resolver chain, SSH argument parser, config loading, setup wizard, shortcut normalization, and shell hook install/uninstall.
|
||||
|
||||
## Disclaimer
|
||||
|
||||
@@ -246,6 +398,6 @@ This is a **vibe-coded** project: the entire codebase — architecture, implemen
|
||||
1. `netssh` checks whether the first argument is a known subcommand (`configure`, `search`, `cache`, `completion`). If not, it enters SSH wrapper mode.
|
||||
2. On first run or when `netbox.url` is empty, the interactive setup wizard starts automatically.
|
||||
3. It parses the SSH arguments to extract the destination hostname, handling all flags that consume an extra argument (`-p`, `-i`, `-J`, …).
|
||||
4. It checks the local cache. If the entry exists and is within the TTL, it connects immediately.
|
||||
4. It resolves the destination: first an exact cache lookup, then shortcut expansion (domain append, hyphen folding) against the cache, and finally a fresh NetBox query with the expanded name. If the cache entry is within the TTL, no network request is made.
|
||||
5. Otherwise it queries NetBox (`/api/dcim/devices/` and `/api/virtualization/virtual-machines/` in parallel), runs the result through the resolver chain, and caches the IP.
|
||||
6. It calls `syscall.Exec` to replace itself with `ssh`, substituting the hostname with the resolved IP.
|
||||
|
||||
Reference in New Issue
Block a user