Add README, LICENSE (GPL-3), and update config dir to XDG path

Config moved to ~/.config/portainer-cli/config.yml following XDG convention.
README covers installation, configuration, all commands, container name
resolution logic, and debugging. Tool noted as AI-generated.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-22 15:18:27 +01:00
parent 56f73f72e0
commit f263088d15
3 changed files with 177 additions and 1 deletions
+26
View File
@@ -0,0 +1,26 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2026 Grzegorz Luszczek
Everyone is permitted to copy and distribute verbatim copies of this license
document, but changing it is not allowed.
PREAMBLE
The GNU General Public License is a free, copyleft license for software and
other kinds of works.
When we speak of free software, we are referring to freedom, not price. Our
General Public Licenses are designed to make sure that you have the freedom
to distribute copies of free software (and charge for them if you wish), that
you receive source code or can get it if you want it, that you can change the
software or use pieces of it in new free programs, and that you know you can
do these things.
To protect your rights, we need to prevent others from denying you these
rights or asking you to surrender the rights. Therefore, you have certain
responsibilities if you distribute copies of the software, or if you modify
it: responsibilities to respect the freedom of others.
For the full license text, see: https://www.gnu.org/licenses/gpl-3.0.txt
+150
View File
@@ -0,0 +1,150 @@
# portainer-cli
A Ruby command-line tool for interacting with [Portainer](https://www.portainer.io/) via its REST API. List environments, stacks, containers, volumes and networks — and open fully interactive shells inside running containers directly from your terminal.
> **This tool was fully generated by AI** (Claude, by Anthropic) through an iterative conversation-driven development session.
## Features
- List endpoints, stacks, containers, volumes, and networks
- Create stacks (from file or inline compose) and containers
- **Interactive exec into containers** via WebSocket — works like `docker exec -it` but through Portainer
- Smart container name resolution: fuzzy matching using Docker Compose naming conventions (`<stack>-<service>-<N>`)
- Automatic endpoint resolution — no need to look up endpoint IDs manually
- Supports both API key and JWT token authentication
- Configurable SSL verification (useful for self-signed certificates)
- `--run CMD` flag for running a specific command (e.g. `rails c`)
- `--quiet` flag for scripting and AI agent use cases
## Requirements
- Ruby 3.x
- [`websocket`](https://rubygems.org/gems/websocket) gem
- A running Portainer instance (v2.x or later)
## Installation
```sh
git clone https://github.com/grzlus/portainer-cli
cd portainer-cli
bundle install
chmod +x bin/portainer-cli
# Link into your PATH (adjust the target to wherever suits you)
ln -sf "$PWD/bin/portainer-cli" ~/bin/portainer-cli
```
## Configuration
```sh
portainer-cli configure
```
You will be prompted for:
- **Portainer URL** — e.g. `https://portainer.example.com`
- **Authentication** — API key (recommended, no expiry) or JWT token
- **SSL verification** — answer `n` if your instance uses a self-signed certificate
Configuration is saved to `~/.config/portainer-cli/config.yml` (mode `0600`).
### Manual config
```yaml
# ~/.config/portainer-cli/config.yml
url: https://portainer.example.com
api_key: ptr_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
ssl_verify: true
```
## Usage
### List resources
```sh
portainer-cli list endpoints
portainer-cli list stacks
portainer-cli list containers <endpoint-id>
portainer-cli list volumes <endpoint-id>
portainer-cli list networks <endpoint-id>
```
### Open an interactive shell
```sh
# Resolves endpoint automatically from the stack name.
# Container name defaults to the stack name, then falls back to 'app'.
portainer-cli console <stack>
portainer-cli console <stack> <container>
# Examples
portainer-cli console myapp
portainer-cli console myapp worker
portainer-cli console myapp --shell /bin/bash
```
### Run a specific command
```sh
portainer-cli console myapp --run "rails c"
portainer-cli console myapp --run "bundle exec rake db:migrate"
```
### Quiet mode (scripting / AI agents)
Suppresses all status output — only the container's own stdout/stderr is printed.
```sh
portainer-cli console myapp --quiet --run "rails runner 'puts User.count'"
```
### Create resources
```sh
# Stack from a compose file
portainer-cli create stack --endpoint 1 --name myapp --file docker-compose.yml
# Stack from inline compose
portainer-cli create stack --endpoint 1 --name myapp --compose "version: '3'
services:
web:
image: nginx"
# Container
portainer-cli create container --endpoint 1 --image nginx:alpine --name web \
--port 8080:80 --env APP_ENV=production
```
### Low-level exec (manual endpoint ID)
```sh
portainer-cli exec <endpoint-id> <container-name-or-id>
portainer-cli exec <endpoint-id> <container-name-or-id> --shell /bin/bash
```
## Container name resolution
When using `console`, names are resolved in this order:
1. **Exact match** — full container name or ID prefix
2. **Compose pattern**`<stack>-<service>-<N>` (e.g. `librarian``librarian-librarian-1`)
3. **Substring match** — scoped to the stack's own containers
4. **`app` fallback** — tries `<stack>-app-1` as a last resort
If multiple containers match ambiguously, a list is printed and the command exits.
## Debugging
```sh
portainer-cli --debug console myapp
```
Prints the WebSocket URL, auth headers, and the full HTTP upgrade handshake request/response — useful for diagnosing connection issues behind reverse proxies.
## License
This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later version.
See [LICENSE](LICENSE) for the full text.
+1 -1
View File
@@ -5,7 +5,7 @@ require 'fileutils'
module PortainerCli
class Config
CONFIG_DIR = File.expand_path('~/.portainer-cli').freeze
CONFIG_DIR = File.expand_path('~/.config/portainer-cli').freeze
CONFIG_FILE = File.join(CONFIG_DIR, 'config.yml').freeze
attr_accessor :url, :token, :api_key, :ssl_verify