diff --git a/danix/app.py b/danix/app.py new file mode 100644 index 0000000..cd9402f --- /dev/null +++ b/danix/app.py @@ -0,0 +1,7 @@ +import os, sys, django + +sys.dont_write_bytecode = True + +# Django specific settings +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'settings') +django.setup() \ No newline at end of file diff --git a/danix/asgi.py b/danix/asgi.py new file mode 100644 index 0000000..9bd043b --- /dev/null +++ b/danix/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for danix project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'settings') + +application = get_asgi_application() diff --git a/danix/danixfs.py b/danix/danixfs.py new file mode 100644 index 0000000..31ea415 --- /dev/null +++ b/danix/danixfs.py @@ -0,0 +1,62 @@ +import uuid, os, settings, app +from time import sleep + +class Danix(): + + @staticmethod + def rm(filesystem_name): + return os.system(f"rm {filesystem_name}") + + @staticmethod + def snapshot(filesystem_name): + return os.system(f"tar -czf /opt/danix/{filesystem_name}.tar.gz /opt/danix/{filesystem_name}") + + @staticmethod + def stop(filesystem_name): + + print("Wait a minute: Stoping subsystem") + resp = Danix.snapshot(filesystem_name) + os.system(f"rm -r /opt/danix/{filesystem_name}") + + return resp + + @staticmethod + def start(filesystem_name): + + print("Wait a minute: Starting subsystem") + os.system(f"mkdir /opt/danix/{filesystem_name}") + resp = os.system(f"tar -xf /opt/danix/{filesystem_name}.tar.gz -C /opt/danix/{filesystem_name} > /dev/null") + os.system(f"rm -r /opt/danix/{filesystem_name}.tar.gz > /dev/null") + return resp + + @staticmethod + def navigate(filesystem_uuid): + + return os.system(f"chroot /opt/danix/{filesystem_uuid}/danixfs sh /opt/danix/init.d/init.sh") + + @staticmethod + def build_environment(packages, filesystem_uuid): + filesystem = filesystem_uuid + + os.system(f"mkdir /tmp/{filesystem}") + os.system(f"curl --silent -LO --output-dir /tmp/{filesystem} {settings.REPO_NAME}/{settings.ROOT_FS}") + os.system(f"tar -xf /tmp/{filesystem}/{settings.ROOT_FS} -C /tmp/{filesystem}") + os.system(f"rm /tmp/{filesystem}/{settings.ROOT_FS}") + os.system(f"mv /tmp/{filesystem} /opt/danix/") + + + print("\nPlease! Wait a moment!!") + print("Building container:") + print(f"Installing {len(packages)} packages\n") + + for package in packages: + os.system(f"chroot /opt/danix/{filesystem}/danixfs apk add {package}") + + + os.system(f"chroot /opt/danix/{filesystem}/danixfs apk add ruby") + os.system(f"chroot /opt/danix/{filesystem}/danixfs gem install lolcat") + + print(f"Environment builded succesfully!") + print("0 erros reported!") + + Danix.navigate(filesystem) \ No newline at end of file diff --git a/danix/db/migrations/0001_initial.py b/danix/db/migrations/0001_initial.py new file mode 100644 index 0000000..725947f --- /dev/null +++ b/danix/db/migrations/0001_initial.py @@ -0,0 +1,29 @@ +# Generated by Django 4.2.1 on 2023-05-14 11:45 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Environment', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('filesystem_name', models.UUIDField()), + ('status', models.BooleanField(default=True)), + ('name', models.TextField()), + ('created', models.DateField(default=datetime.datetime(2023, 5, 14, 11, 45, 17, 278286))), + ('template', models.TextField(default='')), + ], + options={ + 'db_table': 'environment', + }, + ), + ] diff --git a/danix/db/migrations/__init__.py b/danix/db/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/danix/db/models.py b/danix/db/models.py new file mode 100644 index 0000000..87c6842 --- /dev/null +++ b/danix/db/models.py @@ -0,0 +1,123 @@ +from django.db import models +from danixfs import Danix +from datetime import datetime +from django.core.exceptions import ValidationError + + +class Environment(models.Model): + filesystem_name = models.UUIDField() + status = models.BooleanField(default=True) + name = models.TextField() + created = models.DateField(default=datetime.now()) + template = models.TextField(default="") + + @staticmethod + def navigate(filesystem_name): + + try: + environment = Environment.objects.filter(filesystem_name=filesystem_name) + + if environment.count() == 0: + print("Environment doenst exist!") + exit(1) + else: + resp = Danix.navigate(filesystem_name) + + if resp != 0: + print("Error!") + exit(1) + except ValidationError as error: + print("Environment doenst exist!") + exit(1) + + @staticmethod + def rm_environment(filesystem_name): + + environment = Environment.objects.filter(filesystem_name=filesystem_name) + + if environment.count() == 0: + print("Environment doesnt exist!") + exit(1) + else: + + Danix.rm(filesystem_name) + env = environment.first() + env.delete() + print("Environment removed successfully!") + exit(0) + + + @staticmethod + def start_environment(filesystem_name): + + environment = Environment.objects.filter(filesystem_name=filesystem_name) + + if environment.count() == 0: + + print("Environment doesnt exist!") + exit(1) + else: + resp = Danix.start(filesystem_name) + if resp == 0: + env = environment.first() + env.status = True + env.save() + print("Environment started successfully!") + exit(0) + else: + print("Starting error!") + exit(1) + + @staticmethod + def set_active(filesystem_name): + environment = Environment.objects.filter(filesystem_name=filesystem_name).first() + + environment.status = True + environment.save() + + @staticmethod + def stop_environment(filesystem_name): + + resp = Danix.stop(filesystem_name) + + if resp == 0: + environment = Environment.objects.filter(filesystem_name=filesystem_name) + + if environment.count() == 0: + print("Environment doesnt exist!") + exit(1) + else: + env = environment.first() + + env.status = False + env.save() + + print("Environment stopped successfully!") + exit(0) + + @staticmethod + def list_environments(): + + environments = Environment.objects.all() + print("==================================================================================================================================") + print("ENVIRONMENT NAME | TEMPLATE | CREATED | CONTAINER NAME | IMAGE | STATUS") + print("==================================================================================================================================") + + if environments.count() > 0: + for environment in environments: + name = str(environment.name) + status_icon = "🟢 Running" if environment.status else "🔴 Stopped" + repeat = (11-len(name)) * '.' + + template = str(environment.template) + + repeat_template = (6-len(template)) * ' ' + + print(f"{name[0:11]}{repeat} {template}{repeat_template} {environment.created} {environment.filesystem_name} Alpine {status_icon}") + + print("==================================================================================================================================") + + + class Meta: + db_table = "environment" +# Create your models here. \ No newline at end of file diff --git a/danix/main.py b/danix/main.py new file mode 100644 index 0000000..4f0d81a --- /dev/null +++ b/danix/main.py @@ -0,0 +1,59 @@ +import argparse, os +import app +from utils import is_root +from templates import Languanges + +from db.models import Environment + +if not is_root(): + print("Please run this program with sudo!") + exit(0) + +parser = argparse.ArgumentParser(prog="Danix", add_help=True) + +usages = parser.add_argument_group("usages") + +usages.add_argument("-l", "--list", action="store_true" , help="List all environments avaliable", required=False) +usages.add_argument("-S", "--start", help="Start system environment", required=False) +usages.add_argument("-s", "--stop", help="Stop system environment", required=False) +usages.add_argument("-r", "--rm", help="Remove system environment", required=False) +usages.add_argument("-n", "--navigate", help="Navigate inside the environment", required=False) + +createenv = parser.add_argument_group("createenv") + +createenv.add_argument("-o", "--option", choices=["clike", "java", "python", "ruby"], required=False) +#fullstack_package = parser.add_argument_group("WebStack", "") + +#fullstack_package.add_argument("-d","--db", type=str, required=False) +#fullstack_package.add_argument("-w", "--webserver", type=str, required=False) +#fullstack_package.add_argument("-f", "--framework", type=str, required=False) +#fullstack_package.add_argument("-e", "--env_name", type=str, required=False) + +args = parser.parse_args() + +languanges_and_softwares = { + "clike" : Languanges.CLike(), + "java" : Languanges.Java(), + "python" : Languanges.Python(), + #"ruby" : Languanges.Ruby() + } + +if args.option: + + name = input("Please enter environment name: ") + languanges_and_softwares.get(args.option).install(name, args.option) + +if args.navigate: + Environment.navigate(args.navigate) + +if args.start: + Environment.start_environment(args.start) + +if args.list: + Environment.list_environments() + +if args.rm: + Environment.rm_environment(args.rm) + +if args.stop: + Environment.stop_environment(args.stop) \ No newline at end of file diff --git a/danix/manage.py b/danix/manage.py new file mode 100755 index 0000000..1b243ab --- /dev/null +++ b/danix/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/danix/requirements.txt b/danix/requirements.txt new file mode 100644 index 0000000..6763591 --- /dev/null +++ b/danix/requirements.txt @@ -0,0 +1,3 @@ +django +argparse +django-environ \ No newline at end of file diff --git a/danix/settings.py b/danix/settings.py new file mode 100644 index 0000000..4fb2269 --- /dev/null +++ b/danix/settings.py @@ -0,0 +1,133 @@ +""" +Django settings for danix project. + +Generated by 'django-admin startproject' using Django 4.2.1. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/4.2/ref/settings/ +""" + +import os, environ +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + +env = environ.Env() + +MAIN_DIR = f"{BASE_DIR}/danix" +environ.Env.read_env(os.path.join(MAIN_DIR, '.env')) + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'django-insecure-emd#8q%fzc#hdb=$ursx36s=qd2)7)q#d@j*(lpzuzja6_39y4' +7 + +REPO_NAME=env('REPO_NAME') +ROOT_FS=env('ROOT_FS') + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'db' +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +#ROOT_URLCONF = 'danix.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/4.2/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + } +} + + +# Password validation +# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/4.2/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/4.2/howto/static-files/ + +STATIC_URL = 'static/' + +# Default primary key field type +# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' \ No newline at end of file diff --git a/danix/templates.py b/danix/templates.py new file mode 100644 index 0000000..49b3827 --- /dev/null +++ b/danix/templates.py @@ -0,0 +1,62 @@ +import uuid, app +from db.models import Environment +from danixfs import Danix + +class Essentials(): + + packages = ["fish", "vim", "nano", "micro", "git"] + +class Languanges(): + + class Python(): + + packages = ["python3", "py3-pip"] + + def install(self, environment_name, template): + filesystem_name = uuid.uuid4() + + environment_count = Environment.objects.filter(filesystem_name=filesystem_name).count() + + if environment_count == 0: + Environment.objects.create(filesystem_name=filesystem_name, template=template, name=environment_name).save() + + joined_packages = self.packages + Essentials().packages + + Environment.set_active(filesystem_name) + Danix.build_environment(joined_packages, filesystem_name) + + class CLike(): + + packages = ["gcc", "g++", "clang", "rust cargo"] + + def install(self, environment_name, template): + filesystem_name = uuid.uuid4() + + environment_count = Environment.objects.filter(filesystem_name=filesystem_name).count() + + if environment_count == 0: + + Environment.objects.create(filesystem_name=filesystem_name, template=template, name=environment_name).save() + + joined_packages = self.packages + Essentials().packages + + Environment.set_active(filesystem_name) + Danix.build_environment(joined_packages, filesystem_name) + + class Java(): + + packages = ["openjdk8", "openjdk11", "openjdk17"] + + def install(self, environment_name, template): + filesystem_name = uuid.uuid4() + + environment_count = Environment.objects.filter(filesystem_name=filesystem_name).count() + + if environment_count == 0: + + Environment.objects.create(filesystem_name=filesystem_name, template=template, name=environment_name).save() + + joined_packages = self.packages + Essentials().packages + + Environment.set_active(filesystem_name) + Danix.build_environment(joined_packages, filesystem_name) \ No newline at end of file diff --git a/danix/utils.py b/danix/utils.py new file mode 100644 index 0000000..1ad15a6 --- /dev/null +++ b/danix/utils.py @@ -0,0 +1,4 @@ +import os + +def is_root(): + return True if os.geteuid() == 0 else False \ No newline at end of file diff --git a/danix/wsgi.py b/danix/wsgi.py new file mode 100644 index 0000000..6a64371 --- /dev/null +++ b/danix/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for danix project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'settings') + +application = get_wsgi_application()