https://github.com/joknarf/pywebexec
Simple and Powerful Python HTTP(S) API/Web interface to Terminal share / Remote execution
https://github.com/joknarf/pywebexec
ansible-killer api-server batch-manager https-server parallel-execution remote-command swagger-ui terminal terminal-share tty web-interface webserver xterm
Last synced: 16 days ago
JSON representation
Simple and Powerful Python HTTP(S) API/Web interface to Terminal share / Remote execution
- Host: GitHub
- URL: https://github.com/joknarf/pywebexec
- Owner: joknarf
- License: mit
- Created: 2025-01-08T15:09:42.000Z (6 months ago)
- Default Branch: main
- Last Pushed: 2025-04-17T19:36:55.000Z (3 months ago)
- Last Synced: 2025-05-07T05:49:15.961Z (2 months ago)
- Topics: ansible-killer, api-server, batch-manager, https-server, parallel-execution, remote-command, swagger-ui, terminal, terminal-share, tty, web-interface, webserver, xterm
- Language: JavaScript
- Homepage:
- Size: 9.23 MB
- Stars: 5
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
[](https://pypi.org/project/pywebexec/)

[](https://shields.io/)
[](https://pepy.tech/projects/pywebexec)
[](https://shields.io/)# pywebexec
Simple Python HTTP(S) API/Web Server Command Launcher and Terminal sharing* build a Restfull API/swagger-ui powered application in no time exposing simple commands/parameters.
* create a toolbox with batch management/parallel execution of commands
* share a terminal in one command
## Install
```
$ pip install pywebexec
```## Quick start
* share terminal
* start http server and spawn a new terminal shared on 0.0.0.0 port 8080 (defaults)
* exiting terminal stops server/share
```shell
$ pywebexec shareterm
```* serve executables
* put in a directory the scripts/commands/links to commands you want to expose
* start http server serving current directory executables listening on 0.0.0.0 port 8080
```shell
$ pywebexec -d
```* Launch commands with params/view live output/Status using browser
* Share your terminal output using `pywebexec -d term`
all commands output / statuses are available in the executables directory in subdirectory `.web_status`
## features
* Serve executables in a directory
* full API driven with dynamic swagger UI
* Launch commands with params from web browser or API call
* multiple share terminal output
* Follow live output
* Replay terminal history
* Stop command
* Relaunch command
* HTTPS support
* HTTPS self-signed certificate generator
* Basic Auth
* LDAP(S) password check/group member
* Safe url token generation
* Can be started as a daemon (POSIX)
* Uses gunicorn to serve http/https
* Linux/MacOS compatible
* Markdown help for commands
* YAML schema for commands parameters
* Batch/parallel command execution## Customize server
```shell
$ pywebexec --dir ~/myscripts --listen 0.0.0.0 --port 8080 --title myscripts
$ pywebexec -d ~/myscripts -l 0.0.0.0 -p 8080 -t myscripts
```## Sharing terminals
* start server and share tty in one command
```shell
$ pywebexec -d ~/webshare shareterm
```
* share tty with an already pywebexec server started
```shell
$ pywebexec -d ~/webshare term
```
if another user need to share his terminal, he need to have write permission on `/.web_status` directory.## Safe url token
* generate safe url, use the url to access the server
```shell
$ pywebexec -T
$ pywebexec --tokenurl
Starting server:
http://:8080?token=jSTWiNgEVkddeEJ7I97x2ekOeaiXs2mErRSKNxm3DP0
http://x.x.x.x:8080?token=jSTWiNgEVkddeEJ7I97x2ekOeaiXs2mErRSKNxm3DP0
```## Basic auth
* single user/password
```shell
$ pywebexec --user myuser [--password mypass]
$ pywebexec -u myuser [-P mypass]
```
Generated password is given if no `--pasword` option* ldap(s) password check / group member
ldap server must accept memberOf attribute for group members
```shell
$ export PYWEBEXEC_LDAP_SERVER=ldaps://ldap.mydomain.com:389
$ export PYWEBEXEC_LDAP_BIND_DN="cn=read-only-admin,dc=example,dc=com"
$ export PYWEBEXEC_LDAP_BIND_PASSWORD="password"
$ export PYWEBEXEC_LDAP_BASE_DN="dc=example,dc=com"
$ export PYWEBEXEC_LDAP_USER_ID="uid" # sAMAccountName for AD
$ export PYWEBEXEC_LDAP_GROUPS="ou=mathematicians,dc=example,dc=com ou=scientists,dc=example,dc=com"
$ pywebexec
```
## HTTPS server* Generate auto-signed certificate and start https server
```shell
$ pywebexec --gencert
$ pywebexec --g
```* Start https server using existing certificate
```shell
$ pywebexec --cert /pathto/host.cert --key /pathto/host.key
$ pywebexec -c /pathto/host.cert -k /pathto/host.key
```## Launch server as a daemon
```shell
$ pywebexec start
$ pywebexec status
$ pywebexec stop
```
* log of server are stored in directory `~/[.config/].pywebexec/pywebexec_:.log`## Launch command through API
```shell
$ curl http://myhost:8080/commands/myscript -H 'Content-Type: application/json' -X POST -d '{"params":["param1", ...]}'
$ curl http://myhost:8080/commands/
$ curl http://myhost:8080/commands//output -H "Accept: text/plain"
```## Add markdown help to commands
For each exposed command, you can add a help message by creating a file named `.help` in the same directory as the command. The help message must be written in markdown.
The help message is displayed:
* in the web interface as tooltip when focused on param input field,
* in the response when calling the API `/executables`
* in the swagger-ui in the `/commands/` route.
## Add schema to commands
For each exposed command, you can add a schema by creating a file named `.schema.yaml` in the same directory as the command. The schema must be written in yaml format.
The schema is used to generate a form in the web interface and in the swagger-ui in the `/commands/` route.
The schema is also used to validate the input parameters when calling the API `/commands/`.
The schema must be written in the openapi schema format.```yaml
type: object
properties:
param1:
type: string
description: "param1 description"
example: "value"
param2:
type: integer
description: "param2 description"
enum: [1, 2, 3]
param3:
type: array
items:
type: string
description: "param3 description"
example: ["value1", "value2"]
required:
- param1
- param2
```
The payload will be converted to command line arguments when calling the command.
```
command --param1 value --param2 1 --param3 value1 value2
```* On the web inferface, and swagger-ui the form will be generated from the schema.
When using schema, the command can now be launched with:
```
$ curl -X POST http:///commands/ -H "Content-Type: application/json" -d '{"param1": "value", "param2": 1, "param3": ["value1", "value2"]}'
```## Schema options
The schema options are used to customize the command line arguments generation, just add a `schema_options` section to the schema.
```yaml
schema_options:
separator_params: {"*": " ", "param2": "="}}"=" # --param2=value (default is " ")
noprefix_params: ["param1", "param2"] # omit --param prefix, use "*" to omit all
convert_params: {"param1": "param2"} # convert param1 to param2
```## Batch commands/parallel execution
Integration of [run-para](https://github.com/joknarf/run-para) to enable batch execution of commands:
* In `schema_options` adding `batch_param` will enable batch mode for the command, the command will be executed for each value in the `batch_param` list.
* The `batch_param` is the name of the parameter that will be used to pass the different values for the parameter.
* The `batch_param` type will be transformed to textarea to provide list to use as parameter for the command.
* The range parameters `parallel` and `delay` is added to the command parameters to control the execution of the batch commands (nb jobs in parallel and initial delay between jobs).
## Swagger UI
A custom swagger UI is available at `http[s]:///v0/documentation` with enhanced markdown rendering and form generation for body parameters.
## API reference
| method | route | params/payload | returns
|-----------|-----------------------------|--------------------|---------------------|
| GET | /commands/exposed | | commands: [
{
command: str,
help: str
},
] |
| GET | /commands | | commands: [
{
command_id: uuid
command: str
start_time: isotime
end_time: isotime
status: str
exit_code: int
last_output_line: str
},
] |
| GET | /commands/{id} | | command_id: uuid
command: str
params: array[str]
start_time: isotime
end_time: isotime
status: str
exit_code: int
last_output_line: str |
| GET | /commands/{id}/output | offset: int | output: str
status: str
links: { next: str } |
| GET | /commands/{id}/output_raw | offset: int | output: stream raw output until end of command
curl -Ns http://srv/commands/{id}/output_raw|
| POST | /commands | command: str
params: array[str]
rows: int
cols: int | command_id: uuid
message: str |
| POST | /commands/{cmd} | params: array[str]
rows: int
cols: int | command_id: uuid
message: str |
| PATCH | /commands/{id}/stop | | message: str |* to get command output as text (without ANSI codes/Control characters) use: `/commands/{id}/output` with header `"Accept: text/plain"`