Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 0 additions & 20 deletions labctl/api_driver.py

This file was deleted.

1 change: 1 addition & 0 deletions labctl/commands/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .config import app as config_app
70 changes: 70 additions & 0 deletions labctl/commands/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import typer

from rich.table import Table

from labctl.core import Config, APIDriver, console


app = typer.Typer()

@app.command(name="show")
def show():
"""
Show the current configuration
"""
config = Config()
api_token = config.api_token
if api_token:
me = APIDriver().get("/me")
# todo handle old token and valid token
if me.get("email"):
api_token = "Logged in as " + me["email"]
else:
api_token = "Token is invalid or expired (use `labctl login`)"
else:
api_token = "Not logged in"
table = Table(title="Configuration")
table.add_column("Key", style="cyan")
table.add_column("Value", style="magenta")
table.add_row("API URL", config.api_endpoint)
table.add_row("API Token", api_token)
console.print(table)

if not config.api_endpoint:
console.print("[red]Warning: API Endpoint not set. Use `labctl config set --api-endpoint=<server>` [/red]")
if not config.api_token:
console.print("[red]Warning: API Token not set. Use `labctl login`. [/red]")

@app.command(name="set")
def set_config(
api_endpoint: str = typer.Option(None, help="Set the API endpoint")
):
"""
Set the configuration
"""
new_config = {}
if api_endpoint:
new_config["api_endpoint"] = api_endpoint
if not new_config:
console.print("[red]No settings provided[/red]")
raise typer.Abort()
Config(**new_config).save()
console.print("[green]Configuration updated[/green]")
show()

@app.command(name="unset")
def unset_config(
api_endpoint: bool = typer.Option(False, help="Unset the API endpoint")
):
"""
Unset the configuration
"""
new_config = {}
if api_endpoint:
new_config["api_endpoint"] = None
if not new_config:
console.print("[red]No settings provided[/red]")
raise typer.Abort()
Config(**new_config).save()
console.print("[green]Configuration updated[/green]")
show()
55 changes: 0 additions & 55 deletions labctl/config.py

This file was deleted.

4 changes: 4 additions & 0 deletions labctl/core/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from .config import Config
from .api import APIDriver
from .console import console
from .decorators import cli_ready
33 changes: 33 additions & 0 deletions labctl/core/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import requests
import typer
from labctl import __version__
from labctl.core import Config


class APIDriver:

api_url: str = None
api_token: str = None
headers: dict = None

def __init__(self):
config: Config = Config()
self.api_url = config.api_endpoint
if self.api_url.endswith("/"):
self.api_url = self.api_url.rstrip("/")
self.headers = {
'accept': 'application/json',
'User-Agent': 'labctl/' + __version__,
'Authorization': f'Bearer {config.api_token}'
}

def validate_token(self):
return self.get("/token/verify").get("valid", False)

def get(self, path: str):
return requests.get(self.api_url + path, headers=self.headers).json()

def post(self, path: str, data: dict = {}, additional_headers: dict = {}):
headers = self.headers
headers.update(additional_headers)
return requests.post(self.api_url + path, headers=headers, data=data).json()
56 changes: 56 additions & 0 deletions labctl/core/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from pathlib import Path

import yaml

CONFIG_LOCATION_DIR = f"{Path.home()}/"
CONIIG_FILE = ".labctl_config.yaml"

class Config:

api_endpoint: str
api_token: str
token_type: str

def __init__(self, **kwargs):
"""
Initialize the configuration object
The kwargs are used to update the configuration on fly like so:
config = Config(api_endpoint="http://localhost:8000").save()
"""
if not Path(CONFIG_LOCATION_DIR).exists():
Path(CONFIG_LOCATION_DIR).mkdir(parents=True)

# If the config file does not exist, create a new one else load the existing one
if not Path(CONFIG_LOCATION_DIR + CONIIG_FILE).exists():
self.save()
else:
self.load()
self.__dict__.update(kwargs)

def __getattr__(self, name):
"""
Get the value of the attribute or return None if it does not exist
"""
return self.__dict__.get(name, None)

def save(self):
"""
Save the current configuration to the configuration file
"""
with open(CONFIG_LOCATION_DIR + CONIIG_FILE, "w") as stream:
yaml.dump(self.__dict__, stream)
return self

def load(self):
"""
Load the configuration from the configuration file
"""
with open(CONFIG_LOCATION_DIR + CONIIG_FILE, "r") as stream:
self.__dict__.update(yaml.load(stream, Loader=yaml.FullLoader))
return self

def ready(self):
"""
Check if the configuration is ready to be used
"""
return all([self.api_endpoint, self.api_token, self.token_type])
5 changes: 5 additions & 0 deletions labctl/core/console.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from rich.console import Console

console = Console(
color_system="auto",
)
26 changes: 26 additions & 0 deletions labctl/core/decorators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from functools import wraps

import typer
from labctl.core import APIDriver, Config, console

def cli_ready(func):
"""
Decorator to check if the CLI is ready to be used
Validates the configuration have been token and url set and check if token is still valid
"""
@wraps(func)
def wrapper(*args, **kwargs):
try:
config = Config()
if not config.ready():
console.print("[red]Configuration not ready, please run 'labctl config show' to check the current configuration[/red]")
raise typer.Exit(1)
api_driver = APIDriver()
if not api_driver.validate_token():
console.print("[red]Token is not valid, please run 'labctl config show' to check the current configuration[/red]")
raise typer.Exit(1)
return func(*args, **kwargs)
except Exception as e:
typer.echo(f"Error: {e}")
raise typer.Exit(1)
return wrapper
Loading