New API for dev mode (dummy platform), dev tools, auth cmd prototype #9

Merged
MOIS3Y merged 6 commits from MOIS3Y/isp-maintenance:api into main 2024-06-04 23:53:30 +08:00
9 changed files with 291 additions and 0 deletions
Showing only changes of commit 287216d975 - Show all commits

13
Makefile Normal file
View File

@ -0,0 +1,13 @@
build:
python3 ./scripts/devtools/dev.py builder docker-compose build
destroy:
python3 ./scripts/devtools/dev.py builder docker-compose destroy
up:
python3 ./scripts/devtools/dev.py runner docker-compose up
down:
python3 ./scripts/devtools/dev.py runner docker-compose down
restart:
python3 ./scripts/devtools/dev.py runner docker-compose restart
setup: build up
.PHONY: exec setup build

59
docker-compose.yml Normal file
View File

@ -0,0 +1,59 @@
# ? docker-compose.yml for development environment
# ! To start development you need to create a directory ./dummy_platform.
# ? Place files from the test platform into it:
# ? VM6:
# ? /opt/ispsystem/vm/config.json - configuration file
# ? /opt/ispsystem/vm/mysql - database directory
# ? DCI6:
# ? /opt/ispsystem/dci/config.json - configuration file
# ? /opt/ispsystem/dci/mysql - database directory
# ? Create ./.env file and fill it with required vars:
# ? PLATFORM_TYPE='vm'
# ? Database container:
# ? MYSQL_DATABASE="database name"
# ? MYSQL_ROOT_PASSWORD="super secret password from config.json"
# ? Launch:
# ? docker-compose up -d --force-recreate
# ? docker attach mgrctl
services:
mgrctl:
container_name: mgrctl
restart: unless-stopped
build:
context: .
args:
- APP_VERSION=${APP_VERSION}
- APP_DIR=${APP_DIR}
- SRC_DIR=${SRC_DIR}
- PKG_NAME=${PKG_NAME}
- PKG_VERSION=${PKG_VERSION}
networks:
vm_box_net: null
volumes:
- type: bind
source: ./dummy_platform/opt/ispsystem/${PLATFORM_TYPE}/config.json
target: /opt/ispsystem/${PLATFORM_TYPE}/config.json
env_file:
- ./.env
tty: true
stdin_open: true
mysql:
container_name: mysql
image: docker-registry.ispsystem.com/mysql:5
volumes:
- ./dummy_platform/opt/ispsystem/${PLATFORM_TYPE}/mysql:/var/lib/mysql
env_file:
- ./.env
labels:
autoconf_mysql: "true"
networks:
vm_box_net: null
command: --group-concat-max-len=131072 --max-connections=1000 --optimizer-search-depth=0
networks:
vm_box_net:
driver: bridge

View File

@ -0,0 +1,10 @@
# █▀▄▀█ █▀▀ ▀█▀ ▄▀█ ▀
# █░▀░█ ██▄ ░█░ █▀█ ▄
# -- -- -- -- -- -- -
__author__ = "MOIS3Y"
__credits__ = ["Stepan Zhukovsky"]
__license__ = "MIT"
__version__ = "0.1.0"
__maintainer__ = "Stepan Zhukovsky"
__email__ = "stepan@zhukovsky.me"
__status__ = "Development"

View File

@ -0,0 +1,50 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import click
import sh
from .lazy_group import LazyGroup
from .utils import abort_if_false
from . import settings
@click.group()
def cli1():
pass
@click.group(
cls=LazyGroup,
lazy_subcommands={'docker-compose': 'cli.builder.docker_compose'},
)
def cli2():
pass
@click.group(help='cmd for build/destroy project in docker containers')
def docker_compose():
pass
@docker_compose.command(help='cmd for build project in docker containers')
def build():
with sh.contrib.sudo(password=settings.SUDO_PASSWORD, _with=True):
sh.docker_compose('-f', settings.COMPOSE_FILE, 'build', _fg=True)
@docker_compose.command(help='cmd for destroy project in docker containers')
@click.option(
'--yes',
is_flag=True,
callback=abort_if_false,
expose_value=False,
prompt='Are you sure you want to destroy docker containers')
def destroy():
with sh.contrib.sudo(password=settings.SUDO_PASSWORD, _with=True):
sh.docker_compose('-f', settings.COMPOSE_FILE, 'down', _fg=True)
cli = click.CommandCollection(
sources=[cli1, cli2],
help='cmd for building the project'
)

View File

@ -0,0 +1,39 @@
import importlib
import click
class LazyGroup(click.Group):
def __init__(self, *args, lazy_subcommands=None, **kwargs):
super().__init__(*args, **kwargs)
# lazy_subcommands is a map of the form:
#
# {command-name} -> {module-name}.{command-object-name}
#
self.lazy_subcommands = lazy_subcommands or {}
def list_commands(self, ctx):
base = super().list_commands(ctx)
lazy = sorted(self.lazy_subcommands.keys())
return base + lazy
def get_command(self, ctx, cmd_name):
if cmd_name in self.lazy_subcommands:
return self._lazy_load(cmd_name)
return super().get_command(ctx, cmd_name)
def _lazy_load(self, cmd_name):
# lazily loading a command,
# first get the module name and attribute name
import_path = self.lazy_subcommands[cmd_name]
modname, cmd_object_name = import_path.rsplit(".", 1)
# do the import
mod = importlib.import_module(modname)
# get the Command object from that module
cmd_object = getattr(mod, cmd_object_name)
# check the result to make debugging easier
if not isinstance(cmd_object, click.BaseCommand):
raise ValueError(
f"Lazy loading of {import_path} failed by returning "
"a non-command object"
)
return cmd_object

View File

@ -0,0 +1,57 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import click
import sh
from .lazy_group import LazyGroup
from . import settings
@click.group()
def cli1():
pass
@click.group(
cls=LazyGroup,
lazy_subcommands={'docker-compose': 'cli.runner.docker_compose'},
)
def cli2():
pass
@click.group(help='cmd for run/stop/restart project in docker containers')
def docker_compose():
pass
@docker_compose.command(help='cmd for run project docker containers')
def up():
with sh.contrib.sudo(password=settings.SUDO_PASSWORD, _with=True):
sh.docker_compose('-f', settings.COMPOSE_FILE, 'up', '-d', _fg=True)
@docker_compose.command(help='cmd for down project docker containers')
def down():
with sh.contrib.sudo(password=settings.SUDO_PASSWORD, _with=True):
sh.docker_compose('-f', settings.COMPOSE_FILE, 'down', _fg=True)
@docker_compose.command(help='cmd for restart project docker containers')
def restart():
with sh.contrib.sudo(password=settings.SUDO_PASSWORD, _with=True):
sh.docker_compose(
'-f',
settings.COMPOSE_FILE,
'up',
'-d',
'--build',
'--force-recreate',
_fg=True
)
cli = click.CommandCollection(
sources=[cli1, cli2],
help='cmd for running the project standalone or docker-compose'
)

View File

@ -0,0 +1,18 @@
import pathlib
from environs import Env
# Path:
ROOT_DIR = pathlib.Path(__file__).resolve().parent.parent.parent.parent
PROJECT_DIR = ROOT_DIR / 'mgrctl'
COMPOSE_FILE = ROOT_DIR / 'docker-compose.yml'
# Init environment:
env = Env()
# read .env file, if it exists
# reed more about .env file here: https://github.com/sloria/environs
env.read_env(path=ROOT_DIR / '.env')
# ! insecure save sudo password wherever
SUDO_PASSWORD = env.str('SUDO_PASSWORD', None)

View File

@ -0,0 +1,15 @@
import click
from . import __version__
def print_version(ctx, param, value):
if not value or ctx.resilient_parsing:
return
click.echo(__version__)
ctx.exit()
def abort_if_false(ctx, param, value):
if not value:
ctx.abort()

30
scripts/devtools/dev.py Executable file
View File

@ -0,0 +1,30 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import click
from cli.lazy_group import LazyGroup
from cli.utils import print_version
@click.group(
cls=LazyGroup,
lazy_subcommands={
'builder': 'cli.builder.cli',
'runner': 'cli.runner.cli',
},
help='dev.py CLI tool for dev actions',
)
@click.option(
'--version',
is_flag=True,
callback=print_version,
expose_value=False,
is_eager=True,
help='Print version and exit'
)
def cli():
pass
if __name__ == '__main__':
cli()