Beginning a CLI client application using the client library.
This commit is contained in:
@@ -6,3 +6,4 @@ BTrees
|
||||
transaction
|
||||
ZEO
|
||||
podman
|
||||
click
|
||||
@@ -1 +1 @@
|
||||
VERSION="0.3.0-alpha"
|
||||
VERSION="0.4.0-alpha"
|
||||
45
src/packetserver/client/cli/__init__.py
Normal file
45
src/packetserver/client/cli/__init__.py
Normal file
@@ -0,0 +1,45 @@
|
||||
import click
|
||||
from packetserver.client.cli.config import get_config, default_app_dir, config_path
|
||||
from packetserver.client.cli.constants import DEFAULT_DB_FILE
|
||||
import ZODB
|
||||
import ZODB.FileStorage
|
||||
import sys
|
||||
import os
|
||||
import os.path
|
||||
from pathlib import Path
|
||||
from packetserver.client import Client
|
||||
from packetserver.client.users import get_user_by_username, UserWrapper
|
||||
|
||||
VERSION="0.1.0-alpha"
|
||||
|
||||
|
||||
|
||||
@click.group()
|
||||
@click.option('--conf', default=config_path(), help='path to configfile')
|
||||
@click.option('--server', '-s', default='', help="server radio callsign to connect to (required)")
|
||||
@click.option('--agwpe', '-a', default='localhost', help="AGWPE TNC server address to connect to (config file)")
|
||||
@click.option('--port', '-p', default=8000, help="AGWPE TNC server port to connect to (config file)")
|
||||
@click.option('--callsign', '-c', default='', help="radio callsign[+ssid] of this client station (config file)")
|
||||
@click.version_option(VERSION,"--version", "-v")
|
||||
@click.pass_context
|
||||
def cli(ctx, conf, server, agwpe, port, callsign):
|
||||
"""Command line interface for the PacketServer client and server API."""
|
||||
cfg = get_config(config_file_path=conf)
|
||||
storage = ZODB.FileStorage.FileStorage(os.path.join(cfg['cli']['directory'], DEFAULT_DB_FILE))
|
||||
db = ZODB.DB(storage)
|
||||
ctx.ensure_object(dict)
|
||||
ctx.obj['CONFIG'] = cfg
|
||||
ctx.obj['bbs'] = server
|
||||
ctx.obj['db'] = db
|
||||
|
||||
@click.command()
|
||||
@click.option('--username', '-u', default='', help="the username (CALLSIGN) to lookup on the bbs")
|
||||
@click.pass_context
|
||||
def user(ctx):
|
||||
"""Query users on the BBS and customize personal settings."""
|
||||
pass
|
||||
|
||||
cli.add_command(user)
|
||||
|
||||
if __name__ == '__main__':
|
||||
cli()
|
||||
0
src/packetserver/client/cli/bulletin.py
Normal file
0
src/packetserver/client/cli/bulletin.py
Normal file
24
src/packetserver/client/cli/config.py
Normal file
24
src/packetserver/client/cli/config.py
Normal file
@@ -0,0 +1,24 @@
|
||||
import os
|
||||
import os.path
|
||||
from configparser import ConfigParser
|
||||
from pathlib import Path
|
||||
from packetserver.client.cli.constants import DEFAULT_APP_DIR, DEFAULT_CONFIG_FILE
|
||||
|
||||
def default_app_dir() -> str:
|
||||
return os.path.join(str(Path.home()), DEFAULT_APP_DIR)
|
||||
|
||||
def config_path(app_path=default_app_dir()) -> str:
|
||||
return os.path.join(app_path, DEFAULT_CONFIG_FILE)
|
||||
|
||||
def get_config(config_file_path=config_path()) -> ConfigParser:
|
||||
config = ConfigParser()
|
||||
if os.path.isfile(config_file_path):
|
||||
config.read(config_file_path)
|
||||
|
||||
if not 'cli' in config.sections():
|
||||
config.add_section('cli')
|
||||
|
||||
if 'directory' not in config['cli']:
|
||||
config['cli']['directory'] = default_app_dir()
|
||||
|
||||
return config
|
||||
5
src/packetserver/client/cli/constants.py
Normal file
5
src/packetserver/client/cli/constants.py
Normal file
@@ -0,0 +1,5 @@
|
||||
import os.path
|
||||
|
||||
DEFAULT_APP_DIR = ".packetserver"
|
||||
DEFAULT_CONFIG_FILE = "cli.ini"
|
||||
DEFAULT_DB_FILE = "cli-client.zopedb"
|
||||
0
src/packetserver/client/cli/db.py
Normal file
0
src/packetserver/client/cli/db.py
Normal file
0
src/packetserver/client/cli/job.py
Normal file
0
src/packetserver/client/cli/job.py
Normal file
0
src/packetserver/client/cli/message.py
Normal file
0
src/packetserver/client/cli/message.py
Normal file
0
src/packetserver/client/cli/object.py
Normal file
0
src/packetserver/client/cli/object.py
Normal file
0
src/packetserver/client/cli/server.py
Normal file
0
src/packetserver/client/cli/server.py
Normal file
7
src/packetserver/client/cli/util.py
Normal file
7
src/packetserver/client/cli/util.py
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -119,14 +119,25 @@ def send_job_quick(client: Client, bbs_callsign: str, cmd: Union[str, list], db:
|
||||
def get_job_id(client: Client, bbs_callsign: str, job_id: int, get_data=True) -> JobWrapper:
|
||||
req = Request.blank()
|
||||
req.path = f"job/{job_id}"
|
||||
req.set_var('data', get_data)
|
||||
req.method = Request.Method.GET
|
||||
response = client.send_receive_callsign(req, bbs_callsign)
|
||||
if response.status_code != 200:
|
||||
raise RuntimeError(f"Sending job failed: {response.status_code}: {response.payload}")
|
||||
raise RuntimeError(f"GET job {job_id} failed: {response.status_code}: {response.payload}")
|
||||
return JobWrapper(response.payload)
|
||||
|
||||
def get_user_jobs(): # TODO
|
||||
pass
|
||||
def get_user_jobs(client: Client, bbs_callsign: str, get_data=True) -> list[JobWrapper]:
|
||||
req = Request.blank()
|
||||
req.path = f"job/user"
|
||||
req.set_var('data', get_data)
|
||||
req.method = Request.Method.GET
|
||||
response = client.send_receive_callsign(req, bbs_callsign)
|
||||
if response.status_code != 200:
|
||||
raise RuntimeError(f"GET user jobs failed: {response.status_code}: {response.payload}")
|
||||
jobs = []
|
||||
for j in response.payload:
|
||||
jobs.append(JobWrapper(j))
|
||||
return jobs
|
||||
|
||||
class JobSession:
|
||||
def __init__(self, client: Client, bbs_callsign: str, default_timeout: int = 300, stutter: int = 2):
|
||||
|
||||
@@ -25,7 +25,7 @@ from threading import Thread
|
||||
from packetserver.server.jobs import get_orchestrator_from_config, Job, JobStatus
|
||||
from packetserver.runner import RunnerStatus, RunnerFile, Orchestrator, Runner
|
||||
|
||||
VERSION="0.2.0-alpha"
|
||||
VERSION="0.4.0-alpha"
|
||||
|
||||
def init_bulletins(root: PersistentMapping):
|
||||
if 'bulletins' not in root:
|
||||
@@ -103,7 +103,7 @@ class Server:
|
||||
if 'runner' in conn.root.config['jobs_config']:
|
||||
val = str(conn.root.config['jobs_config']['runner']).lower().strip()
|
||||
if val in ['podman']:
|
||||
logging.debug("Enabling podman orchestrator")
|
||||
logging.debug(f"Enabling {val} orchestrator")
|
||||
self.orchestrator = get_orchestrator_from_config(conn.root.config['jobs_config'])
|
||||
|
||||
self.app = pe.app.Application()
|
||||
|
||||
@@ -18,7 +18,7 @@ import gzip
|
||||
import tarfile
|
||||
import time
|
||||
import json
|
||||
from packetserver.runner.podman import TarFileExtractor, PodmanOrchestrator, PodmanRunner, PodmanOptions
|
||||
from packetserver.common.util import TarFileExtractor
|
||||
from packetserver.runner import Orchestrator, Runner, RunnerStatus, RunnerFile
|
||||
from enum import Enum
|
||||
from io import BytesIO
|
||||
@@ -38,6 +38,7 @@ def get_orchestrator_from_config(cfg: dict) -> Union[Orchestrator, PodmanOrchest
|
||||
if 'runner' in cfg:
|
||||
val = cfg['runner'].lower().strip()
|
||||
if val == "podman":
|
||||
from packetserver.runner.podman import PodmanOrchestrator, PodmanOptions
|
||||
image = cfg.get('image', 'debian')
|
||||
opts = PodmanOptions(default_timeout=300, max_timeout=3600, image_name=image, max_active_jobs=5,
|
||||
container_keepalive=300, name_prefix="packetserver_")
|
||||
|
||||
22
src/packetserver/setup.py
Normal file
22
src/packetserver/setup.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name='packetserver',
|
||||
version='VERSION="0.4.0-alpha',
|
||||
packages=find_packages(),
|
||||
include_package_data=True,
|
||||
install_requires=[
|
||||
'click',
|
||||
'pyham_pe',
|
||||
'msgpack',
|
||||
'pyham_ax25',
|
||||
'ZODB',
|
||||
'ZEO',
|
||||
'podman'
|
||||
],
|
||||
entry_points={
|
||||
'console_scripts': [
|
||||
'packcli = packetserver.client.cli:cli',
|
||||
],
|
||||
},
|
||||
)
|
||||
Reference in New Issue
Block a user