Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge_config #12

Merged
merged 2 commits into from
Nov 17, 2023
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
89 changes: 64 additions & 25 deletions uplib/uplib/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,80 @@
from dynaconf.loaders import yaml_loader
from enum import Enum

class Config(Enum):
# (key, default_value)
default_image = ("default_image", "fedora")
welcome_message = ("welcome_message", "Thank your for running UP!")
log_level = ("log_level", "INFO", logging.getLevelName)
volumes = ("volumes", {})
ports = ("ports", {})

__settings = None

#TODO: Add optional prompt
class Settings:
_settings = {}

settings = None

@classmethod
def settings(cls):
_settings = Config.__settings
if not _settings:
_settings = Dynaconf(
def of_default_settings(cls):
settings = Settings._settings.get("__DEFAULT__")
if not settings:
logging.info("Loading default settings")
settings = Dynaconf(
environments=False,
envvar_prefix="UP")
up_yaml = pkgutil.get_data(__name__, "up.yaml")
if up_yaml:
up_yaml = up_yaml.decode("utf-8")
yaml_loader.load(_settings, filename=up_yaml)
return _settings
yaml_loader.load(settings, filename=up_yaml)
Settings._settings["__DEFAULT__"] = settings
return settings

@classmethod
def prefix_for(cls, plugin_mod):
plugin_name = plugin_mod.__name__
plugin_name = plugin_name.replace("-", "_")
plugin_name = plugin_name.upper()
return plugin_name

@classmethod
def of_plugin_settings(cls, plugin_name, settings_path):
settings = Settings._settings.get(plugin_name)
if not settings:
env_prefix = Settings.prefix_for(plugin_name)
settings = Dynaconf(
load_dotenv=True,
envvar_prefix=env_prefix,
settings_file=settings_path,)
Settings._settings[plugin_name] = settings
return settings

def __init__(self, plugin_name = None, settings_path = None):
if plugin_name:
self.settings = Settings.of_plugin_settings(plugin_name, settings_path)
else:
self.settings = Settings.of_default_settings()

def settings(self) -> Dynaconf:
return self.settings

def get(self, config_enum):
config = config_enum.value
default_val = config[1] if len(config) > 1 else None
config_key = config[0]
result = self._settings.get(config_key, default_val)
if result:
converter = config[2] if len(config) > 2 else None
if converter:
result = converter(result)
return result

class Config(Enum):
# (key, default_value)
default_image = ("default_image", "fedora")
welcome_message = ("welcome_message", "Thank your for running UP!")
log_level = ("log_level", "INFO")
volumes = ("volumes", {})
ports = ("ports", {})
prompts = ("prompts", [])

# Gets a configuration value from default settings
def get(self):
value = self.value
key = value[0]
result = Config.settings().get(key)
if not result:
result = value[1] if len(value) > 1 else None
converter = value[2] if len(value) > 2 else None
if converter and result:
result = converter(result)
result = Settings().get(self)
return result


def get_log_level():
return Config.log_level.get()

Expand Down
36 changes: 33 additions & 3 deletions uplib/uplib/containers.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import re
import os
import docker
import subprocess
from rich.console import Console
Expand Down Expand Up @@ -29,8 +30,25 @@ class ContainerRun:


class DockerContainers:
@classmethod
def volumes_of(cls, run:ContainerRun):
settings_vols = settings_maps.get("volumes", {})
cwd = os.getcwd()
home = os.path.expanduser("~")
default_vols = {
home : {
"bind": "/tmp/up_home",
"mode": "rw"
},
cwd : {
"bind": "/tmp/up_cwd",
"mode": "rw"
}
}
result = settings_vols | default_vols
return result

def run(self, run: ContainerRun):
log.info("Running container: %s", run)
client = docker.from_env()
#TODO: Catch errors, print properly, pass all params
#TODO: Locate bash properly
Expand All @@ -40,15 +58,27 @@ def run(self, run: ContainerRun):
command = ["sh", "-c", subprocess.list2cmdline(command)]
log.debug("$: %s", run)
name = run.name if run.name else generate_container_name(run)
volumes = DockerContainers.volumes_of(run)
ports = settings_maps.get("ports")
console = Console()
console.log(f"Running container: {name}")
console.log({
"name": name,
"image": run.image,
"command": command,
"auto_remove": run.auto_remove,
"volumes": volumes,
"ports": ports,
"detach": True
})
try:
container = client.containers.run(
name=name,
image=run.image,
command= command,
auto_remove=run.auto_remove,
volumes=settings_maps.get("volumes"),
ports=settings_maps.get("ports"),
volumes=volumes,
ports=ports,
detach=True
)
for line in container.logs(stream=True):
Expand Down
14 changes: 13 additions & 1 deletion uplib/uplib/logging.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
import sys
import logging
from .config import get_log_level
from rich.logging import RichHandler

TRACE = 5

def init_logging():
sys.set_int_max_str_digits(999999)
level = get_log_level()
logging.basicConfig(stream=sys.stderr, level=level)
print("Initializing logging with level "+str(level))
logging.basicConfig(
level=level
)
#TODO: Configure rich log handler
# https://rich.readthedocs.io/en/stable/logging.html
log = logging.getLogger("up")
log.setLevel(level)
# print("Testing logging PRINT at level "+str(level))
# log.info("Testing logging INFO at level "+str(level))
# log.error("Testing logging ERROR at level "+str(level))
# log.debug("Testing logging DEBUG at level "+str(level))
# log.warning("Testing logging WARNING at level "+str(level))
return log

log = init_logging()
29 changes: 7 additions & 22 deletions uplib/uplib/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@
import os
import pluggy
import json
from dynaconf import Dynaconf

from . import settings_maps
from .containers import Containers
from .hookspecs import containers_for_prompt
from .logging import log
from .config import Config
from .config import Settings, Config


def load_plugins(context):
Expand Down Expand Up @@ -52,36 +51,20 @@ def load_plugin(plugin_name, plugin_dir):
plugin_name, plugin_dir)
except Exception as e:
log.error("Error loading plugin %s: %s", plugin_name, str(e))
raise e
plugin_name = None
return (plugin_name, settings_file)


def load_settings(plugin_name, settings_path):
env_prefix = prefix_for(plugin_name)
settings = Dynaconf(
load_dotenv=True,
envvar_prefix=env_prefix,
settings_file=settings_path,)
settings = Settings(plugin_name, settings_path)
prompts = settings.get(Config.prompts)
# Load Environment Variables
prompts = settings.get("prompts", [])
log.debug("Loading %s prompts: %s", len(prompts), prompts)
load_prompts(prompts)
#load_volumes()
#load_ports()
# Load Ports
# ...
log.debug("Settings loaded")
settings_json = json.dumps(settings_maps, indent=2)
log.info("Loaded settings\n%s", settings_json)
log.info("Loaded settings for plugin %s@%s\n%s", plugin_name, settings_path, str(settings))
return settings


def prefix_for(plugin_mod):
plugin_name = plugin_mod.__name__
plugin_name = plugin_name.replace("-", "_")
plugin_name = plugin_name.upper()
return plugin_name

def load_prompts(prompts):
for prompt_cfg in prompts:
load_prompt(prompt_cfg)
Expand Down Expand Up @@ -130,6 +113,8 @@ def load_ports():
settings_maps["ports"] = Config.ports.get()

def settings(prompt):
#TODO: Delegate to Settings.of_prompt(prompt)
#TODO: Create type-safe PromptConfig enum?
settings_map = settings_maps.get(prompt)
if not settings_map:
settings_map = {}
Expand Down
Loading