diff --git a/.gitignore b/.gitignore index 6b5c4123..0261fe23 100644 --- a/.gitignore +++ b/.gitignore @@ -76,3 +76,4 @@ default.db private.py venv/ venv3/ +test-manifest/ diff --git a/drydock/manifest_builder/infrastructure/flex_tutor_manifest.py b/drydock/manifest_builder/infrastructure/flex_tutor_manifest.py new file mode 100644 index 00000000..54618ec8 --- /dev/null +++ b/drydock/manifest_builder/infrastructure/flex_tutor_manifest.py @@ -0,0 +1,41 @@ +import os + +from abc import abstractmethod +from drydock.manifest_builder.domain.config import DrydockConfig +from drydock.manifest_builder.domain.manifest_repository import ManifestRepository + +from tutor import env as tutor_env +from tutor import hooks + + +class FlexibleTutorManifest(ManifestRepository): + + def save(config: DrydockConfig) -> None: + + # import pudb; pu.db + env = config.get_data() + + # Render the manifest by reusing the code that tutor uses for the env + fixed_root = "test-manifest" + # tutor_env.save(context.obj.root, config) + + def my_base_dir(root): + """Return the environment base directory.""" + return os.path.join(fixed_root, "") + + tutor_env.base_dir = my_base_dir + tutor_env.save(None, env) + + + hooks.filters.clear("env:templates:targets") + name = "drydock" + hooks.filters.add_items( + "env:templates:targets", + [ + ( + os.path.join(name, "manifest_001"), + "", + ), + ], + ) + tutor_env.save(None, env) diff --git a/drydock/manifest_builder/infrastructure/tutor_config.py b/drydock/manifest_builder/infrastructure/tutor_config.py new file mode 100644 index 00000000..47ba8d6f --- /dev/null +++ b/drydock/manifest_builder/infrastructure/tutor_config.py @@ -0,0 +1,13 @@ +from abc import abstractmethod +from tutor import config as tutor_config +from drydock.manifest_builder.domain.config import DrydockConfig + + +class TutorConfig(DrydockConfig): + + def __init__(self, context): + self.context = context + + def get_data(self) -> dict: + config = tutor_config.load_full(self.context.obj.root) + return config diff --git a/setup.py b/setup.py new file mode 100644 index 00000000..aaafba16 --- /dev/null +++ b/setup.py @@ -0,0 +1,59 @@ +import io +import os +from setuptools import setup, find_packages + +HERE = os.path.abspath(os.path.dirname(__file__)) + + +def load_readme(): + with io.open(os.path.join(HERE, "README.rst"), "rt", encoding="utf8") as f: + return f.read() + + +def load_about(): + about = {} + with io.open( + os.path.join(HERE, "tutor_plugin", "__about__.py"), + "rt", + encoding="utf-8", + ) as f: + exec(f.read(), about) # pylint: disable=exec-used + return about + + +ABOUT = load_about() + + +setup( + name="drydock", + version=ABOUT["__version__"], + url="https://github.com/edunext/drydock", + project_urls={ + "Code": "https://github.com/edunext/drydock", + "Issue tracker": "https://github.com/edunext/drydock/issues", + }, + license="AGPLv3", + author="eduNEXT", + description="Manifest builder for k8s Open edX hosting", + long_description=load_readme(), + packages=find_packages(exclude=["tests*"]), + include_package_data=True, + python_requires=">=3.7", + install_requires=["tutor"], + entry_points={ + "tutor.plugin.v1": [ + "drydock = tutor_plugin.plugin" + ] + }, + classifiers=[ + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "License :: OSI Approved :: GNU Affero General Public License v3", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + ], +) diff --git a/tutor_plugin/__about__.py b/tutor_plugin/__about__.py new file mode 100644 index 00000000..3dc1f76b --- /dev/null +++ b/tutor_plugin/__about__.py @@ -0,0 +1 @@ +__version__ = "0.1.0" diff --git a/tutor_plugin/__init__.py b/tutor_plugin/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tutor_plugin/patches/.gitignore b/tutor_plugin/patches/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/tutor_plugin/plugin.py b/tutor_plugin/plugin.py new file mode 100644 index 00000000..591ab51b --- /dev/null +++ b/tutor_plugin/plugin.py @@ -0,0 +1,96 @@ +from glob import glob +import os +import pkg_resources + +from tutor import hooks + +from .__about__ import __version__ + + +import click + + +################# Configuration +config = { + # Add here your new settings + "defaults": { + "VERSION": __version__, + }, + # Add here settings that don't have a reasonable default for all users. For + # instance: passwords, secret keys, etc. + "unique": { + # "SECRET_KEY": "\{\{ 24|random_string \}\}", + }, + # Danger zone! Add here values to override settings from Tutor core or other plugins. + "overrides": { + "PLATFORM_NAME": "My platform as defined in plugin.py", + }, +} + + +@click.group(name="drydock", short_help="Manage drydock") +@click.pass_context +def drydock_command(context): + pass + + +@click.command(name="save") +@click.pass_context +def save(context): + + from drydock.manifest_builder.application.manifest_builder import ManifestBuilder + from drydock.manifest_builder.infrastructure import flex_tutor_manifest, tutor_config + + + builder = ManifestBuilder(flex_tutor_manifest.FlexibleTutorManifest) + config = tutor_config.TutorConfig(context=context) + builder(config) + + +drydock_command.add_command(save) + +hooks.filters.add_items( + "cli:commands", + [ + drydock_command, + ], +) + + +################# You don't really have to bother about what's below this line, +################# except maybe for educational purposes :) + +# Plugin templates +hooks.Filters.ENV_TEMPLATE_ROOTS.add_item( + pkg_resources.resource_filename("tutor_plugin", "templates") +) +hooks.Filters.ENV_TEMPLATE_TARGETS.add_items( + [ + ("tutor_plugin/build", "plugins"), + ("tutor_plugin/apps", "plugins"), + ], +) +# Load all patches from the "patches" folder +for path in glob( + os.path.join( + pkg_resources.resource_filename("tutor_plugin", "patches"), + "*", + ) +): + with open(path, encoding="utf-8") as patch_file: + hooks.Filters.ENV_PATCHES.add_item((os.path.basename(path), patch_file.read())) + +# Load all configuration entries +hooks.Filters.CONFIG_DEFAULTS.add_items( + [ + (f"DRYDOCK_{key}", value) + for key, value in config["defaults"].items() + ] +) +hooks.Filters.CONFIG_UNIQUE.add_items( + [ + (f"DRYDOCK_{key}", value) + for key, value in config["unique"].items() + ] +) +hooks.Filters.CONFIG_OVERRIDES.add_items(list(config["overrides"].items())) diff --git a/tutor_plugin/templates/drydock/manifest_001/k8s/other_file.yml b/tutor_plugin/templates/drydock/manifest_001/k8s/other_file.yml new file mode 100644 index 00000000..c303625d --- /dev/null +++ b/tutor_plugin/templates/drydock/manifest_001/k8s/other_file.yml @@ -0,0 +1,12 @@ +--- +# A file that will containt the kustomization + +# can I have access to tutor patches? +{{ patch("kustomization-resources") }} + +# can I have access to tutor vars? +namespace: {{ K8S_NAMESPACE }} + +# can I have access to custom patches? +{{ patch("drydock-patch") }} + diff --git a/tutor_plugin/templates/drydock/manifest_001/kustomization.yml b/tutor_plugin/templates/drydock/manifest_001/kustomization.yml new file mode 100644 index 00000000..c303625d --- /dev/null +++ b/tutor_plugin/templates/drydock/manifest_001/kustomization.yml @@ -0,0 +1,12 @@ +--- +# A file that will containt the kustomization + +# can I have access to tutor patches? +{{ patch("kustomization-resources") }} + +# can I have access to tutor vars? +namespace: {{ K8S_NAMESPACE }} + +# can I have access to custom patches? +{{ patch("drydock-patch") }} +