Skip to content

Commit

Permalink
Merge pull request #12 from CaravanaCloud:merge_config
Browse files Browse the repository at this point in the history
Merge_config
  • Loading branch information
faermanj authored Nov 17, 2023
2 parents 9a4c617 + 03dd8f5 commit 8de2ed3
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 51 deletions.
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

0 comments on commit 8de2ed3

Please sign in to comment.