diff --git a/poc/bin/kroute b/poc/bin/kroute deleted file mode 100755 index f60e9e1..0000000 --- a/poc/bin/kroute +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python - -# -# Copyright 2019 Banco Bilbao Vizcaya Argentaria, S.A. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -import sys - -import click -import requests - -@click.group() -def kroute(): - pass - -@kroute.command() -@click.option("-c", "--command", nargs=1) -@click.option("-e", "--entrypoint", default="/bin/sh -c") -@click.option("-X", "--method", default="GET") -@click.option("--url", envvar='KAPOW_URL') -@click.argument("url_pattern", nargs=1) -@click.argument("command_file", required=False) -def add(url_pattern, entrypoint, command, method, url, command_file): - if command: - # Command is given inline - source = command - elif command_file is None: - # No command - source = "" - elif command_file == '-': - # Read commands from stdin - source = sys.stdin.read() - else: - # Read commands from a file - with open(command_file, 'r', encoding='utf-8') as handler: - source = handler.read() - - response = requests.post(f"{url}/routes", - json={"method": method, - "url_pattern": url_pattern, - "entrypoint": entrypoint, - "command": source}) - response.raise_for_status() - print(response.json()) - - -@kroute.command() -@click.option("--url", envvar='KAPOW_URL') -@click.argument("route-id") -def remove(route_id, url): - response = requests.delete(f"{url}/routes/{route_id}") - response.raise_for_status() - print(response.json()) - - -if __name__ == '__main__': - kroute() diff --git a/poc/examples/eval.pow b/poc/examples/eval.pow index 15fddb4..209be5d 100644 --- a/poc/examples/eval.pow +++ b/poc/examples/eval.pow @@ -16,4 +16,4 @@ # limitations under the License. # -kroute add -X POST '/eval' -c '$($(request /body) | response /stream)' +kapow route add -X POST '/eval' -c '$($(request /body) | response /stream)' diff --git a/poc/examples/nmap/nmap.pow b/poc/examples/nmap/nmap.pow index 6df7789..08748b8 100644 --- a/poc/examples/nmap/nmap.pow +++ b/poc/examples/nmap/nmap.pow @@ -16,4 +16,4 @@ # limitations under the License. # -kroute add -X GET '/list/{ip}' -c 'nmap -sL $(request /match/ip) | response /body' +kapow route add -X GET '/list/{ip}' -c 'nmap -sL $(request /match/ip) | response /body' diff --git a/poc/examples/operator.pow b/poc/examples/operator.pow index 6e86640..4de6391 100755 --- a/poc/examples/operator.pow +++ b/poc/examples/operator.pow @@ -16,26 +16,26 @@ # limitations under the License. # -kroute add /list/files -c 'ls -la $(request /param/path) | response /body' +kapow route add /list/files -c 'ls -la $(request /param/path) | response /body' -kroute add /list/processes -c 'ps -aux | response /body' +kapow route add /list/processes -c 'ps -aux | response /body' -kroute add /show/cpuinfo -c 'response /body < /proc/cpuinfo' +kapow route add /show/cpuinfo -c 'response /body < /proc/cpuinfo' -kroute add /show/memory -c 'free -m | response /body' +kapow route add /show/memory -c 'free -m | response /body' -kroute add /show/disk -c 'df -h | response /body' +kapow route add /show/disk -c 'df -h | response /body' -kroute add /show/connections -c 'ss -pluton | response /body' +kapow route add /show/connections -c 'ss -pluton | response /body' -kroute add /show/mounts -c 'mount | response /body' +kapow route add /show/mounts -c 'mount | response /body' -kroute add /tail/dmesg - <<-'EOF' +kapow route add /tail/dmesg - <<-'EOF' response /header/Content-Type text/plain dmesg -w | response /stream EOF -kroute add /tail/journal - <<-'EOF' +kapow route add /tail/journal - <<-'EOF' response /header/Content-Type text/plain journalctl -f | response /stream EOF diff --git a/poc/examples/pandoc/pandoc.pow b/poc/examples/pandoc/pandoc.pow index 4bd2bbf..a7a433d 100755 --- a/poc/examples/pandoc/pandoc.pow +++ b/poc/examples/pandoc/pandoc.pow @@ -16,11 +16,11 @@ # limitations under the License. # -kroute add -X POST --entrypoint '/bin/zsh -c' '/convert/{from}/{to}' - <<-'EOF' +kapow route add -X POST --entrypoint '/bin/zsh -c' '/convert/{from}/{to}' - <<-'EOF' pandoc --from=$(request /match/from) \ --to=$(request /match/to) \ --output=>(response /body) \ =(request /body) EOF -kroute add -X GET '/formats/input' -c 'pandoc --list-input-formats | response /body' -kroute add -X GET '/formats/output' -c 'pandoc --list-output-formats | grep -v pdf | response /body' +kapow route add -X GET '/formats/input' -c 'pandoc --list-input-formats | response /body' +kapow route add -X GET '/formats/output' -c 'pandoc --list-output-formats | grep -v pdf | response /body' diff --git a/poc/examples/pdfeditor/pdfeditor.pow b/poc/examples/pdfeditor/pdfeditor.pow index 7b26f7e..4bd4703 100644 --- a/poc/examples/pdfeditor/pdfeditor.pow +++ b/poc/examples/pdfeditor/pdfeditor.pow @@ -16,5 +16,5 @@ # limitations under the License. # -kroute add -X POST --entrypoint ./topdf '/editor/pdf' -kroute add / -c 'response /header/Content-Type text/html && response /body < pdfeditor.html' +kapow route add -X POST --entrypoint ./topdf '/editor/pdf' +kapow route add / -c 'response /header/Content-Type text/html && response /body < pdfeditor.html' diff --git a/poc/examples/torrent.pow b/poc/examples/torrent.pow index b6b4a39..ec3ab46 100644 --- a/poc/examples/torrent.pow +++ b/poc/examples/torrent.pow @@ -16,7 +16,7 @@ # limitations under the License. # -kroute add / - <<-'EOF' +kapow route add / - <<-'EOF' response /header/Content-Type text/html response /body <<-HTML @@ -27,7 +27,7 @@ kroute add / - <<-'EOF' HTML EOF -kroute add /save/magnet -e '/bin/bash -c' - <<-'EOF' +kapow route add /save/magnet -e '/bin/bash -c' - <<-'EOF' link=$(request /param/link) [ -z $link ] && response /status 400 && exit 0 @@ -40,4 +40,4 @@ kroute add /save/magnet -e '/bin/bash -c' - <<-'EOF' response /header/Location /torrent/list EOF -kroute add /torrent/list -c 'response /body "Not Implemented Yet"' +kapow route add /torrent/list -c 'response /body "Not Implemented Yet"' diff --git a/poc/kapow b/poc/kapow index c2183c0..99be517 100755 --- a/poc/kapow +++ b/poc/kapow @@ -26,6 +26,9 @@ import shlex import sys from aiohttp import web, StreamReader +import click +import requests + log = logging.getLogger('kapow') @@ -281,22 +284,21 @@ async def delete_route(request): ######################################################################## -async def run_init_script(app): +async def run_init_script(app, scripts): """ Run the init script if given, then wait for the shell to finish. """ - if len(sys.argv) == 1: + if not scripts: # No script given cmd = "/bin/bash" - elif len(sys.argv) == 2: - cmd = f"/bin/bash --init-file {sys.argv[1]}" else: - print(f"Usage: {sys.argv[0]} ") - os._exit(1) + filenames = " ".join(shlex.quote(f) for f in scripts) + cmd = f"/bin/bash --init-file <(cat {filenames})" shell_task = await asyncio.create_subprocess_shell( cmd, + executable="/bin/bash", env={**os.environ, "KAPOW_URL": "http://localhost:8080/kapow" }) @@ -308,11 +310,10 @@ async def run_init_script(app): async def start_background_tasks(app): loop = asyncio.get_running_loop() - app["debug_tasks"] = loop.create_task(run_init_script(app)) + app["debug_tasks"] = loop.create_task(run_init_script(app, app["scripts"])) -def kapow(): - """Start aiohttp app.""" +def start_kapow_server(scripts): app = web.Application(client_max_size=1024**3) app.add_routes([ web.get('/kapow/routes', get_routes), @@ -322,9 +323,72 @@ def kapow(): # web.post('/kapow/connections/{id}/{field:.*}', append_field), web.put('/kapow/connections/{id}/{field:.*}', set_field), ]) + app["scripts"] = scripts app.on_startup.append(start_background_tasks) web.run_app(app) +######################################################################## +# Command Lineagement # +######################################################################## + + +@click.group() +@click.pass_context +def kapow(ctx): + """Start aiohttp app.""" + pass + + +@kapow.command() +@click.argument("scripts", nargs=-1) +def server(scripts): + start_kapow_server(scripts) + +@kapow.group() +def route(): + pass + + +@route.command() +@click.option("-c", "--command", nargs=1) +@click.option("-e", "--entrypoint", default="/bin/sh -c") +@click.option("-X", "--method", default="GET") +@click.option("--url", envvar='KAPOW_URL') +@click.argument("url_pattern", nargs=1) +@click.argument("command_file", required=False) +def add(url_pattern, entrypoint, command, method, url, command_file): + if command: + # Command is given inline + source = command + elif command_file is None: + # No command + source = "" + elif command_file == '-': + # Read commands from stdin + source = sys.stdin.read() + else: + # Read commands from a file + with open(command_file, 'r', encoding='utf-8') as handler: + source = handler.read() + + response = requests.post(f"{url}/routes", + json={"method": method, + "url_pattern": url_pattern, + "entrypoint": entrypoint, + "command": source}) + response.raise_for_status() + print(response.json()) + + +@route.command() +@click.option("--url", envvar='KAPOW_URL') +@click.argument("route-id") +def remove(route_id, url): + response = requests.delete(f"{url}/routes/{route_id}") + response.raise_for_status() + print(response.json()) + + if __name__ == '__main__': kapow() diff --git a/spec/README.md b/spec/README.md index f9d18d4..5e5c474 100644 --- a/spec/README.md +++ b/spec/README.md @@ -470,7 +470,7 @@ You can run it by ... Any compliant implementation of Kapow! must provide these commands: -### `kapow` +### `kapow server` This implements the server, XXX