New API for dev mode (dummy platform), dev tools, auth cmd prototype #9
							
								
								
									
										5
									
								
								.dockerignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.dockerignore
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | docker-compose.yml | ||||||
|  | .gitignore | ||||||
|  | .env | ||||||
|  | .git | ||||||
|  | .cache | ||||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -163,3 +163,4 @@ cython_debug/ | |||||||
| 
 | 
 | ||||||
| # Project specific | # Project specific | ||||||
| config.json | config.json | ||||||
|  | **/dummy_platform | ||||||
|  | |||||||
							
								
								
									
										61
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										61
									
								
								Dockerfile
									
									
									
									
									
								
							| @ -1,10 +1,59 @@ | |||||||
|  | # app/Dockerfile | ||||||
|  | 
 | ||||||
|  | # pull the official docker image | ||||||
|  | FROM python:3.11-alpine as poetry-base | ||||||
|  | 
 | ||||||
|  | # default build args | ||||||
|  | ARG APP_VERSION=0.1.0 \ | ||||||
|  |     APP_DIR=/app \ | ||||||
|  |     SRC_DIR=./mgrctl \ | ||||||
|  |     PKG_NAME=mgrctl \ | ||||||
|  |     PKG_VERSION=0.1.0 | ||||||
|  | 
 | ||||||
|  | # set env variables | ||||||
|  | ENV APP_NAME=mgrctl \ | ||||||
|  |     # Python3: | ||||||
|  |     PYTHONFAULTHANDLER=1 \ | ||||||
|  |     PYTHONUNBUFFERED=1 \ | ||||||
|  |     PYTHONHASHSEED=random \ | ||||||
|  |     # Pip: | ||||||
|  |     PIP_NO_CACHE_DIR=on \ | ||||||
|  |     PIP_DISABLE_PIP_VERSION_CHECK=on \ | ||||||
|  |     PIP_ROOT_USER_ACTION=ignore \ | ||||||
|  |     PIP_DEFAULT_TIMEOUT=100 \ | ||||||
|  |     # Poetry: | ||||||
|  |     POETRY_NO_INTERACTION=1 \ | ||||||
|  |     POETRY_VIRTUALENVS_CREATE=false \ | ||||||
|  |     POETRY_CACHE_DIR='/var/cache/pypoetry' \ | ||||||
|  |     POETRY_HOME='/usr/local' \ | ||||||
|  |     POETRY_VERSION=1.7.1 | ||||||
|  | 
 | ||||||
|  | # install system deps | ||||||
|  | RUN apk --no-cache add curl \ | ||||||
|  |     && curl -sSL https://install.python-poetry.org | python3 - \ | ||||||
|  |     && mkdir ${APP_DIR} | ||||||
|  | 
 | ||||||
|  | COPY ./pyproject.toml ./poetry.lock ./README.md ${APP_DIR} | ||||||
|  | COPY ${SRC_DIR} ${APP_DIR}/${PKG_NAME} | ||||||
|  | 
 | ||||||
|  | # set workdir | ||||||
|  | WORKDIR ${APP_DIR} | ||||||
|  | 
 | ||||||
|  | # build pkg whl | ||||||
|  | RUN poetry build --format wheel \ | ||||||
|  |     && pip install ${APP_DIR}/dist/${PKG_NAME}-${PKG_VERSION}-py3-none-any.whl \ | ||||||
|  |     && rm -r /usr/local/venv | ||||||
|  | 
 | ||||||
|  | # now multistage builds | ||||||
| FROM python:3.11-alpine | FROM python:3.11-alpine | ||||||
| 
 | 
 | ||||||
| WORKDIR /app | # copy app and dependences | ||||||
|  | COPY --from=poetry-base /usr/local/ /usr/local/ | ||||||
| 
 | 
 | ||||||
| COPY requirements.txt ./ | # install bash and mgrctl shell completion | ||||||
| RUN pip install --no-cache-dir --root-user-action=ignore -r requirements.txt | RUN apk --no-cache add bash \ | ||||||
|  |     && echo 'eval "$(_MGRCTL_COMPLETE=bash_source mgrctl)"' > ~/.bashrc | ||||||
| 
 | 
 | ||||||
| COPY main.py . | # "demonize" container | ||||||
| 
 | # use docker attach mgrctl or docker exec -it mgrctl mgrctl --help for example | ||||||
| CMD [ "python", "-u", "main.py" ] | CMD [ "bash"] | ||||||
|  | |||||||
							
								
								
									
										13
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								Makefile
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										59
									
								
								docker-compose.yml
									
									
									
									
									
										Normal 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 | ||||||
| @ -1,24 +0,0 @@ | |||||||
| import click |  | ||||||
| 
 |  | ||||||
| from db.vm6.databases import isp_database |  | ||||||
| from db.vm6.models import AuthUser |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| @click.group(help='access command for lazy example') |  | ||||||
| def cli(): |  | ||||||
|     pass |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| @cli.command(help='show all users and their roles on platform (DEMO EXAMPLE)') |  | ||||||
| def users(): |  | ||||||
|     # check and init connection to db: |  | ||||||
|     isp_database.connect() |  | ||||||
|     # get all fields from auth_user table |  | ||||||
|     # SELECT * FROM auth_user; |  | ||||||
|     all_users = AuthUser.select() |  | ||||||
|     # Iterate fields and print to console users' email and role |  | ||||||
|     for user in all_users: |  | ||||||
|         result = f'{user.email} | {user.roles[0]}' |  | ||||||
|         click.echo(result) |  | ||||||
|     # Close connection |  | ||||||
|     isp_database.close() |  | ||||||
| @ -1,12 +0,0 @@ | |||||||
| import click |  | ||||||
| from core.cli.lazy_group import LazyGroup |  | ||||||
| from settings.general import INSTALLED_APPS |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| @click.group( |  | ||||||
|     cls=LazyGroup, |  | ||||||
|     lazy_subcommands=INSTALLED_APPS['vm6'], |  | ||||||
|     help='vm6 command for lazy example', |  | ||||||
| ) |  | ||||||
| def cli(): |  | ||||||
|     pass |  | ||||||
| @ -1,13 +0,0 @@ | |||||||
| import click |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| @click.group(help='nodes command for lazy example') |  | ||||||
| def cli(): |  | ||||||
|     pass |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| @cli.command(name='list') |  | ||||||
| def nodes_list(): |  | ||||||
|     click.echo('NODES LIST: etc...') |  | ||||||
|     for num in range(1, 10): |  | ||||||
|         click.echo(num) |  | ||||||
| @ -1,51 +0,0 @@ | |||||||
| from core.api.base import BaseAPI, BaseAuthAPI, BaseDnsProxyAPI, BaseIpAPI |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class AuthAPI(BaseAuthAPI): |  | ||||||
|     pass |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class BackupAPI(BaseAPI): |  | ||||||
|     def __init__(self, api_url=None, verify_ssl=True): |  | ||||||
|         super().__init__(api_url, verify_ssl) |  | ||||||
|         self.API_VERSION = 'v4' |  | ||||||
|         self.API_DEFINITION = 'backup' |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class DnsProxyAPI(BaseDnsProxyAPI): |  | ||||||
|     pass |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class EserviceAPI(BaseAPI): |  | ||||||
|     def __init__(self, api_url=None, verify_ssl=True): |  | ||||||
|         super().__init__(api_url, verify_ssl) |  | ||||||
|         self.API_DEFINITION = 'eservice' |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class IsoAPI(BaseAPI): |  | ||||||
|     def __init__(self, api_url=None, verify_ssl=True): |  | ||||||
|         super().__init__(api_url, verify_ssl) |  | ||||||
|         self.API_DEFINITION = 'iso' |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class IpmiAPI(BaseAPI): |  | ||||||
|     def __init__(self, api_url=None, verify_ssl=True): |  | ||||||
|         super().__init__(api_url, verify_ssl) |  | ||||||
|         self.API_DEFINITION = 'ipmiproxy' |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class IpAPI(BaseIpAPI): |  | ||||||
|     pass |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class ReportAPI(BaseAPI): |  | ||||||
|     def __init__(self, api_url=None, verify_ssl=True): |  | ||||||
|         super().__init__(api_url, verify_ssl) |  | ||||||
|         self.API_VERSION = 'v4' |  | ||||||
|         self.API_DEFINITION = 'report' |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class UpdaterAPI(BaseAPI): |  | ||||||
|     def __init__(self, api_url=None, verify_ssl=True): |  | ||||||
|         super().__init__(api_url, verify_ssl) |  | ||||||
|         self.API_DEFINITION = 'updater' |  | ||||||
| @ -1,21 +0,0 @@ | |||||||
| #!/usr/bin/env python3 |  | ||||||
| # -*- coding: utf-8 -*- |  | ||||||
| import click |  | ||||||
| 
 |  | ||||||
| from core.cli.lazy_group import LazyGroup |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| @click.group( |  | ||||||
|     cls=LazyGroup, |  | ||||||
|     lazy_subcommands={ |  | ||||||
|         'vm6': 'apps.vm6.commands.cli', |  | ||||||
|         'dci6': 'apps.dci6.commands.cli', |  | ||||||
|     }, |  | ||||||
|     help='main CLI command for lazy example', |  | ||||||
| ) |  | ||||||
| def cli(): |  | ||||||
|     pass |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| if __name__ == '__main__': |  | ||||||
|     cli() |  | ||||||
| @ -1,10 +0,0 @@ | |||||||
| from settings.platform import PLATFORM_TYPE |  | ||||||
| 
 |  | ||||||
| # Name of nginx container: |  | ||||||
| INPUT_HOSTNAME = 'input' if PLATFORM_TYPE == 'vm' else 'dci_input_1' |  | ||||||
| 
 |  | ||||||
| # Port that nginx container is listening: |  | ||||||
| INPUT_PORT = '1500' |  | ||||||
| 
 |  | ||||||
| # Headers for internal auth: |  | ||||||
| HEADERS = {"Internal-Auth": "on", "Accept": "application/json"} |  | ||||||
| @ -1,13 +0,0 @@ | |||||||
| from settings.environment import env |  | ||||||
| from settings.general import BASE_DIR |  | ||||||
| from utils.helpers import parse_json_file |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| PLATFORM_TYPE = env.str('PLATFORM_TYPE', 'vm') |  | ||||||
| 
 |  | ||||||
| PLATFORM_CONFIG = parse_json_file(f'{BASE_DIR}/config.json') |  | ||||||
| 
 |  | ||||||
| PLATFORM_URL = env.url( |  | ||||||
|     'PLATFORM_URL', |  | ||||||
|     f"https://{PLATFORM_CONFIG.get('DomainName' ,'replace.me')}" |  | ||||||
| ) |  | ||||||
							
								
								
									
										15
									
								
								mgrctl/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								mgrctl/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | # █▀▄▀█ █▀▀ ▀█▀ ▄▀█ ▀ | ||||||
|  | # █░▀░█ ██▄ ░█░ █▀█ ▄ | ||||||
|  | # -- -- -- -- -- -- - | ||||||
|  | __author__ = "MOIS3Y, a.garaev, Failak3, Ann_M" | ||||||
|  | __credits__ = [ | ||||||
|  |     "Stepan Zhukovsky", | ||||||
|  |     "Arthur Garaev", | ||||||
|  |     "Vladislav Shmidt", | ||||||
|  |     "Anna Moskovkina" | ||||||
|  | ] | ||||||
|  | __license__ = "MIT" | ||||||
|  | __version__ = "0.1.0" | ||||||
|  | __maintainer__ = "Stepan Zhukovsky" | ||||||
|  | __email__ = "stepan@zhukovsky.me" | ||||||
|  | __status__ = "Development" | ||||||
| @ -3,18 +3,52 @@ import json | |||||||
| import urllib | import urllib | ||||||
| import requests | import requests | ||||||
| 
 | 
 | ||||||
| from settings.api import INPUT_HOSTNAME, INPUT_PORT, HEADERS | from mgrctl.settings.api import INPUT_URL, HEADERS | ||||||
|  | from mgrctl.settings.platform import ( | ||||||
|  |     PLATFORM_TYPE, | ||||||
|  |     PLATFORM_VERIFY_SSL, | ||||||
|  |     PLATFORM_DUMMY, | ||||||
|  |     PLATFORM_DUMMY_VM6_API_URL, | ||||||
|  |     PLATFORM_DUMMY_VM6_EMAIL, | ||||||
|  |     PLATFORM_DUMMY_VM6_PASSWORD, | ||||||
|  |     PLATFORM_DUMMY_VM6_TOKEN, | ||||||
|  |     PLATFORM_DUMMY_DCI6_API_URL, | ||||||
|  |     PLATFORM_DUMMY_DCI6_EMAIL, | ||||||
|  |     PLATFORM_DUMMY_DCI6_PASSWORD, | ||||||
|  |     PLATFORM_DUMMY_DCI6_TOKEN | ||||||
|  | ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class BaseAPI(object): | class BaseAPI(object): | ||||||
|     def __init__(self, api_url=None, verify_ssl=True): |     def __init__(self): | ||||||
|         """Announces required parameters""" |         """Announces required parameters""" | ||||||
|         internal_api_url = f'http://{INPUT_HOSTNAME}:{INPUT_PORT}' |         if PLATFORM_TYPE == 'vm': | ||||||
|         self.API_URL = api_url if api_url else internal_api_url |             if PLATFORM_DUMMY: | ||||||
|  |                 self.API_URL = PLATFORM_DUMMY_VM6_API_URL | ||||||
|  |                 self.AUTH_TYPE = 'Public' | ||||||
|  |                 self.HEADERS = {'x-xsrf-token': PLATFORM_DUMMY_VM6_TOKEN} | ||||||
|  |                 self.EMAIL = PLATFORM_DUMMY_VM6_EMAIL | ||||||
|  |                 self.PASSWORD = PLATFORM_DUMMY_VM6_PASSWORD | ||||||
|  |             else: | ||||||
|  |                 self.API_URL = INPUT_URL | ||||||
|  |                 self.AUTH_TYPE = 'Internal' | ||||||
|  |                 self.HEADERS = HEADERS | ||||||
|  | 
 | ||||||
|  |         if PLATFORM_TYPE == 'dci': | ||||||
|  |             if PLATFORM_DUMMY: | ||||||
|  |                 self.API_URL = PLATFORM_DUMMY_DCI6_API_URL | ||||||
|  |                 self.AUTH_TYPE = 'Public' | ||||||
|  |                 self.HEADERS = {'x-xsrf-token': PLATFORM_DUMMY_DCI6_TOKEN} | ||||||
|  |                 self.EMAIL = PLATFORM_DUMMY_DCI6_EMAIL | ||||||
|  |                 self.PASSWORD = PLATFORM_DUMMY_DCI6_PASSWORD | ||||||
|  |             else: | ||||||
|  |                 self.API_URL = INPUT_URL | ||||||
|  |                 self.AUTH_TYPE = 'Internal' | ||||||
|  |                 self.HEADERS = HEADERS | ||||||
|  | 
 | ||||||
|         self.API_VERSION = 'v3' |         self.API_VERSION = 'v3' | ||||||
|         self.API_DEFINITION = 'api' |         self.API_DEFINITION = 'api' | ||||||
|         self.HEADERS = HEADERS |         self.VERIFY_SSL = PLATFORM_VERIFY_SSL | ||||||
|         self.VERIFY_SSL = verify_ssl |  | ||||||
| 
 | 
 | ||||||
|     def _gen_request_url(self, url): |     def _gen_request_url(self, url): | ||||||
|         return f'{self.API_URL}/{self.API_DEFINITION}/{self.API_VERSION}{url}' |         return f'{self.API_URL}/{self.API_DEFINITION}/{self.API_VERSION}{url}' | ||||||
| @ -63,61 +97,24 @@ class BaseAPI(object): | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class BaseAuthAPI(BaseAPI): | class BaseAuthAPI(BaseAPI): | ||||||
|     def __init__(self, api_url=None, verify_ssl=True): |     def __init__(self): | ||||||
|         """ |         super().__init__() | ||||||
|         Init class for /auth/v4 requests |  | ||||||
| 
 |  | ||||||
|         Args: |  | ||||||
|             api_url (str, optional): url api host. Defaults to None. |  | ||||||
|             If None will use from settings.api.INPUT_HOSTNAME:INPUT_PORT |  | ||||||
| 
 |  | ||||||
|             verify_ssl (bool, optional): Isn't recommended. Defaults to True. |  | ||||||
|             Use only for testing if you don't have root sign SSL cert. |  | ||||||
|         """ |  | ||||||
|         super().__init__(api_url, verify_ssl) |  | ||||||
|         self.API_VERSION = 'v4' |         self.API_VERSION = 'v4' | ||||||
|         self.API_DEFINITION = 'auth' |         self.API_DEFINITION = 'auth' | ||||||
| 
 | 
 | ||||||
|     def get_auth_token(self, email: str, password: str) -> dict: |     def get_auth_token(self, email=None, password=None) -> dict: | ||||||
|         """ |         email = self.EMAIL if not email else email | ||||||
|         Get auth token for authentication |         password = self.PASSWORD if not password else password | ||||||
| 
 |  | ||||||
|         Arg: |  | ||||||
|             email (str): user email |  | ||||||
|             password (str): user password |  | ||||||
| 
 |  | ||||||
|         Returns: |  | ||||||
|             response (dict): { |  | ||||||
|                 "confirmed": true, |  | ||||||
|                 "expires_at": "date time", |  | ||||||
|                 "id": "int", |  | ||||||
|                 "token": "str" |  | ||||||
|             } |  | ||||||
|         """ |  | ||||||
|         return self.call_api( |         return self.call_api( | ||||||
|             url='/public/token', |             url='/public/token', | ||||||
|             method='POST', |             method='POST', | ||||||
|             data={'email': email, 'password': password} |             data={'email': email, 'password': password} | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|     def get_auth_key(self, token: str, user, auth_type='Internal') -> dict: |     def get_auth_key(self, token=None, user=None) -> dict: | ||||||
|         """ |  | ||||||
|         Key authentication |  | ||||||
| 
 |  | ||||||
|         Args: |  | ||||||
|             token (str): auth token |  | ||||||
|             user (str or int): user id or email |  | ||||||
|             auth_type (str, optional): May be Public for public auth. |  | ||||||
|             Defaults to 'Internal'. |  | ||||||
| 
 |  | ||||||
|         Returns: |  | ||||||
|             response (dict): { |  | ||||||
|                 "id": "int", |  | ||||||
|                 "key": "str" |  | ||||||
|             } |  | ||||||
|         """ |  | ||||||
|         headers = {} |         headers = {} | ||||||
|         if auth_type == 'Public': |         user = self.EMAIL if not user else user | ||||||
|  |         if token: | ||||||
|             headers = self.make_auth_header(token) |             headers = self.make_auth_header(token) | ||||||
|         return self.call_api( |         return self.call_api( | ||||||
|             url=f'/user/{user}/key', |             url=f'/user/{user}/key', | ||||||
| @ -126,32 +123,22 @@ class BaseAuthAPI(BaseAPI): | |||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|     def make_auth_header(self, token: str) -> dict: |     def make_auth_header(self, token: str) -> dict: | ||||||
|         """ |  | ||||||
|         Generate dict for auth header |  | ||||||
| 
 |  | ||||||
|         Args: |  | ||||||
|             token (str): auth token |  | ||||||
| 
 |  | ||||||
|         Returns: |  | ||||||
|             dict: {'x-xsrf-token': token} use it for request headers |  | ||||||
|         """ |  | ||||||
|         return {'x-xsrf-token': token} |         return {'x-xsrf-token': token} | ||||||
| 
 | 
 | ||||||
|     def whoami(self, token: str) -> dict: |     def whoami(self) -> dict: | ||||||
|         return self.call_api( |         return self.call_api( | ||||||
|             url='/whoami', |             url='/whoami', | ||||||
|             method='GET', |             method='GET' | ||||||
|             headers=self.make_auth_header(token) |  | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class BaseIpAPI(BaseAPI): | class BaseIpAPI(BaseAPI): | ||||||
|     def __init__(self, api_url=None, verify_ssl=True): |     def __init__(self): | ||||||
|         super().__init__(api_url, verify_ssl) |         super().__init__() | ||||||
|         self.API_DEFINITION = 'ip' |         self.API_DEFINITION = 'ip' | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class BaseDnsProxyAPI(BaseAPI): | class BaseDnsProxyAPI(BaseAPI): | ||||||
|     def __init__(self, api_url=None, verify_ssl=True): |     def __init__(self): | ||||||
|         super().__init__(api_url, verify_ssl) |         super().__init__() | ||||||
|         self.API_DEFINITION = 'dnsproxy' |         self.API_DEFINITION = 'dnsproxy' | ||||||
							
								
								
									
										51
									
								
								mgrctl/api/dci6.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								mgrctl/api/dci6.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | |||||||
|  | from mgrctl.api.base import BaseAPI, BaseAuthAPI, BaseDnsProxyAPI, BaseIpAPI | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class AuthAPI(BaseAuthAPI): | ||||||
|  |     pass | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class BackupAPI(BaseAPI): | ||||||
|  |     def __init__(self): | ||||||
|  |         super().__init__() | ||||||
|  |         self.API_VERSION = 'v4' | ||||||
|  |         self.API_DEFINITION = 'backup' | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class DnsProxyAPI(BaseDnsProxyAPI): | ||||||
|  |     pass | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class EserviceAPI(BaseAPI): | ||||||
|  |     def __init__(self): | ||||||
|  |         super().__init__() | ||||||
|  |         self.API_DEFINITION = 'eservice' | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class IsoAPI(BaseAPI): | ||||||
|  |     def __init__(self): | ||||||
|  |         super().__init__() | ||||||
|  |         self.API_DEFINITION = 'iso' | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class IpmiAPI(BaseAPI): | ||||||
|  |     def __init__(self): | ||||||
|  |         super().__init__() | ||||||
|  |         self.API_DEFINITION = 'ipmiproxy' | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class IpAPI(BaseIpAPI): | ||||||
|  |     pass | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class ReportAPI(BaseAPI): | ||||||
|  |     def __init__(self): | ||||||
|  |         super().__init__() | ||||||
|  |         self.API_VERSION = 'v4' | ||||||
|  |         self.API_DEFINITION = 'report' | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class UpdaterAPI(BaseAPI): | ||||||
|  |     def __init__(self): | ||||||
|  |         super().__init__() | ||||||
|  |         self.API_DEFINITION = 'updater' | ||||||
| @ -1,4 +1,4 @@ | |||||||
| from core.api.base import BaseAPI, BaseAuthAPI, BaseDnsProxyAPI, BaseIpAPI | from mgrctl.api.base import BaseAPI, BaseAuthAPI, BaseDnsProxyAPI, BaseIpAPI | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class AuthAPI(BaseAuthAPI): | class AuthAPI(BaseAuthAPI): | ||||||
| @ -14,6 +14,6 @@ class IpAPI(BaseIpAPI): | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class VmAPI(BaseAPI): | class VmAPI(BaseAPI): | ||||||
|     def __init__(self, api_url=None, verify_ssl=True): |     def __init__(self): | ||||||
|         super().__init__(api_url, verify_ssl) |         super().__init__() | ||||||
|         self.API_DEFINITION = 'vm' |         self.API_DEFINITION = 'vm' | ||||||
							
								
								
									
										15
									
								
								mgrctl/apps/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								mgrctl/apps/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | # █▀▄▀█ █▀▀ ▀█▀ ▄▀█ ▀ | ||||||
|  | # █░▀░█ ██▄ ░█░ █▀█ ▄ | ||||||
|  | # -- -- -- -- -- -- - | ||||||
|  | __author__ = "MOIS3Y, a.garaev, Failak3, Ann_M" | ||||||
|  | __credits__ = [ | ||||||
|  |     "Stepan Zhukovsky", | ||||||
|  |     "Arthur Garaev", | ||||||
|  |     "Vladislav Shmidt", | ||||||
|  |     "Anna Moskovkina" | ||||||
|  | ] | ||||||
|  | __license__ = "MIT" | ||||||
|  | __version__ = "0.1.0" | ||||||
|  | __maintainer__ = "Stepan Zhukovsky" | ||||||
|  | __email__ = "stepan@zhukovsky.me" | ||||||
|  | __status__ = "Development" | ||||||
							
								
								
									
										15
									
								
								mgrctl/apps/dci6/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								mgrctl/apps/dci6/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | # █▀▄▀█ █▀▀ ▀█▀ ▄▀█ ▀ | ||||||
|  | # █░▀░█ ██▄ ░█░ █▀█ ▄ | ||||||
|  | # -- -- -- -- -- -- - | ||||||
|  | __author__ = "MOIS3Y, a.garaev, Failak3, Ann_M" | ||||||
|  | __credits__ = [ | ||||||
|  |     "Stepan Zhukovsky", | ||||||
|  |     "Arthur Garaev", | ||||||
|  |     "Vladislav Shmidt", | ||||||
|  |     "Anna Moskovkina" | ||||||
|  | ] | ||||||
|  | __license__ = "MIT" | ||||||
|  | __version__ = "0.1.0" | ||||||
|  | __maintainer__ = "Stepan Zhukovsky" | ||||||
|  | __email__ = "stepan@zhukovsky.me" | ||||||
|  | __status__ = "Development" | ||||||
| @ -1,7 +1,7 @@ | |||||||
| import click | import click | ||||||
| 
 | 
 | ||||||
| from core.cli.lazy_group import LazyGroup | from mgrctl.cli.lazy_group import LazyGroup | ||||||
| from settings.general import INSTALLED_APPS | from mgrctl.settings.general import INSTALLED_APPS | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @click.group( | @click.group( | ||||||
							
								
								
									
										15
									
								
								mgrctl/apps/vm6/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								mgrctl/apps/vm6/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | # █▀▄▀█ █▀▀ ▀█▀ ▄▀█ ▀ | ||||||
|  | # █░▀░█ ██▄ ░█░ █▀█ ▄ | ||||||
|  | # -- -- -- -- -- -- - | ||||||
|  | __author__ = "MOIS3Y, a.garaev, Failak3, Ann_M" | ||||||
|  | __credits__ = [ | ||||||
|  |     "Stepan Zhukovsky", | ||||||
|  |     "Arthur Garaev", | ||||||
|  |     "Vladislav Shmidt", | ||||||
|  |     "Anna Moskovkina" | ||||||
|  | ] | ||||||
|  | __license__ = "MIT" | ||||||
|  | __version__ = "0.1.0" | ||||||
|  | __maintainer__ = "Stepan Zhukovsky" | ||||||
|  | __email__ = "stepan@zhukovsky.me" | ||||||
|  | __status__ = "Development" | ||||||
							
								
								
									
										10
									
								
								mgrctl/apps/vm6/auth/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								mgrctl/apps/vm6/auth/__init__.py
									
									
									
									
									
										Normal 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" | ||||||
							
								
								
									
										96
									
								
								mgrctl/apps/vm6/auth/commands.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								mgrctl/apps/vm6/auth/commands.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,96 @@ | |||||||
|  | import click | ||||||
|  | 
 | ||||||
|  | from mgrctl.apps.vm6.auth import __version__ | ||||||
|  | from mgrctl.api.vm6 import AuthAPI | ||||||
|  | from mgrctl.utils.api_users import UserAPI | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | user_cursor = UserAPI(callback_class=AuthAPI) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @click.group(help='auth cmd for auth in VMmanager 6') | ||||||
|  | @click.version_option( | ||||||
|  |     version=__version__, | ||||||
|  |     package_name='mgrctl.apps.vm6.auth', | ||||||
|  |     message=__version__ | ||||||
|  | ) | ||||||
|  | def cli(): | ||||||
|  |     pass | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @cli.group(help='Manage users') | ||||||
|  | def user(): | ||||||
|  |     pass | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @user.command(help='List users') | ||||||
|  | @click.option( | ||||||
|  |     '--all', | ||||||
|  |     is_flag=True, | ||||||
|  |     required=False, | ||||||
|  |     help='Show all users' | ||||||
|  | ) | ||||||
|  | @click.option( | ||||||
|  |     '--admins', | ||||||
|  |     is_flag=True, | ||||||
|  |     required=False, | ||||||
|  |     help='Show all active admins', | ||||||
|  | ) | ||||||
|  | def ls(all, admins): | ||||||
|  |     if all: | ||||||
|  |         user_cursor.echo_users(role='all') | ||||||
|  |     elif admins: | ||||||
|  |         user_cursor.echo_users(role='admin') | ||||||
|  |     else: | ||||||
|  |         user_cursor.echo_users(role='all') | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @user.command(help='Generate access key and return auth link(s)') | ||||||
|  | @click.option( | ||||||
|  |     '--id', | ||||||
|  |     required=False, | ||||||
|  |     type=int, | ||||||
|  |     help='User id' | ||||||
|  | ) | ||||||
|  | @click.option( | ||||||
|  |     '--count', | ||||||
|  |     required=False, | ||||||
|  |     type=int, | ||||||
|  |     help='Number of access keys generated', | ||||||
|  | ) | ||||||
|  | @click.option( | ||||||
|  |     '--random', | ||||||
|  |     is_flag=True, | ||||||
|  |     required=False, | ||||||
|  |     help='Interactive mode, ignores other keys' | ||||||
|  | ) | ||||||
|  | @click.option( | ||||||
|  |     '--interactive', | ||||||
|  |     is_flag=True, | ||||||
|  |     required=False, | ||||||
|  |     help='Interactive mode, ignores other keys' | ||||||
|  | ) | ||||||
|  | def access(id, count, interactive, random): | ||||||
|  |     if id and not count: | ||||||
|  |         keys = user_cursor.get_access_keys(user=id, count=1) | ||||||
|  |         links = user_cursor.gen_access_links(keys) | ||||||
|  |         user_cursor.echo_access_links(links) | ||||||
|  |     elif id and count: | ||||||
|  |         keys = user_cursor.get_access_keys(user=id, count=count) | ||||||
|  |         links = user_cursor.gen_access_links(keys) | ||||||
|  |         user_cursor.echo_access_links(links) | ||||||
|  |     elif interactive: | ||||||
|  |         pass | ||||||
|  |     elif random: | ||||||
|  |         admin = user_cursor.get_first_random_admin() | ||||||
|  |         keys = user_cursor.get_access_keys(user=admin.get('id', 3), count=1) | ||||||
|  |         links = user_cursor.gen_access_links(keys) | ||||||
|  |         user_cursor.echo_access_links(links) | ||||||
|  |     else: | ||||||
|  |         pass | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @user.command(help='Generate API token for mgrctl user') | ||||||
|  | def token(): | ||||||
|  |     token = user_cursor.gen_api_token() | ||||||
|  |     user_cursor.echo_api_token(token) | ||||||
							
								
								
									
										19
									
								
								mgrctl/apps/vm6/commands.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								mgrctl/apps/vm6/commands.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | |||||||
|  | import click | ||||||
|  | 
 | ||||||
|  | from mgrctl.cli.lazy_group import LazyGroup | ||||||
|  | from mgrctl.settings.general import INSTALLED_APPS | ||||||
|  | from mgrctl.apps.vm6 import __version__ | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @click.group( | ||||||
|  |     cls=LazyGroup, | ||||||
|  |     lazy_subcommands=INSTALLED_APPS['vm6'], | ||||||
|  |     help='vm6 command for lazy example', | ||||||
|  | ) | ||||||
|  | @click.version_option( | ||||||
|  |     version=__version__, | ||||||
|  |     package_name='mgrctl', | ||||||
|  |     message=__version__ | ||||||
|  | ) | ||||||
|  | def cli(): | ||||||
|  |     pass | ||||||
| @ -1,5 +1,5 @@ | |||||||
| from peewee import MySQLDatabase, PostgresqlDatabase | from peewee import MySQLDatabase, PostgresqlDatabase | ||||||
| from settings.db import ( | from mgrctl.settings.db import ( | ||||||
|     DB_ENGINE, |     DB_ENGINE, | ||||||
|     DB_HOST, |     DB_HOST, | ||||||
|     DB_PORT, |     DB_PORT, | ||||||
| @ -1,4 +1,4 @@ | |||||||
| from db.connection import guess_database | from mgrctl.db.connection import guess_database | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # The variable will contain an object of | # The variable will contain an object of | ||||||
| @ -11,8 +11,8 @@ from peewee import ( | |||||||
|     TextField, |     TextField, | ||||||
|     SQL |     SQL | ||||||
| ) | ) | ||||||
| from db.common import UnknownField | from mgrctl.db.common import UnknownField | ||||||
| from db.dci6.databases import auth_database | from mgrctl.db.dci6.databases import auth_database | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class BaseModel(Model): | class BaseModel(Model): | ||||||
| @ -1,4 +1,4 @@ | |||||||
| from db.connection import guess_database | from mgrctl.db.connection import guess_database | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # The variable will contain an object of | # The variable will contain an object of | ||||||
| @ -12,8 +12,8 @@ from peewee import ( | |||||||
|     TextField, |     TextField, | ||||||
|     SQL |     SQL | ||||||
| ) | ) | ||||||
| from db.common import UnknownField, JSONField | from mgrctl.db.common import UnknownField, JSONField | ||||||
| from db.vm6.databases import isp_database | from mgrctl.db.vm6.databases import isp_database | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class BaseModel(Model): | class BaseModel(Model): | ||||||
							
								
								
									
										32
									
								
								mgrctl/mgrctl.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										32
									
								
								mgrctl/mgrctl.py
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,32 @@ | |||||||
|  | #!/usr/bin/env python3 | ||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  | 
 | ||||||
|  | # █▀▄▀█ █▀▀ █▀█ █▀▀ ▀█▀ █░░ ▀ | ||||||
|  | # █░▀░█ █▄█ █▀▄ █▄▄ ░█░ █▄▄ ▄ | ||||||
|  | # -- -- -- -- -- -- -- -- -- | ||||||
|  | 
 | ||||||
|  | import click | ||||||
|  | 
 | ||||||
|  | from mgrctl import __version__ | ||||||
|  | from mgrctl.cli.lazy_group import LazyGroup | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @click.group( | ||||||
|  |     cls=LazyGroup, | ||||||
|  |     lazy_subcommands={ | ||||||
|  |         'vm6': 'mgrctl.apps.vm6.commands.cli', | ||||||
|  |         'dci6': 'mgrctl.apps.dci6.commands.cli', | ||||||
|  |     }, | ||||||
|  |     help='main CLI command for lazy example', | ||||||
|  | ) | ||||||
|  | @click.version_option( | ||||||
|  |     version=__version__, | ||||||
|  |     package_name='mgrctl', | ||||||
|  |     message=__version__ | ||||||
|  | ) | ||||||
|  | def cli(): | ||||||
|  |     pass | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | if __name__ == '__main__': | ||||||
|  |     cli() | ||||||
| @ -1,12 +1,12 @@ | |||||||
| from settings.general import BASE_DIR | from mgrctl.settings.general import BASE_DIR | ||||||
| 
 | 
 | ||||||
| from settings.platform import ( | from mgrctl.settings.platform import ( | ||||||
|     PLATFORM_TYPE, |     PLATFORM_TYPE, | ||||||
|     PLATFORM_URL, |     PLATFORM_URL, | ||||||
|     PLATFORM_CONFIG |     PLATFORM_CONFIG | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| from settings.db import( | from mgrctl.settings.db import( | ||||||
|     DB_ENGINE, |     DB_ENGINE, | ||||||
|     DB_HOST, |     DB_HOST, | ||||||
|     DB_PORT, |     DB_PORT, | ||||||
							
								
								
									
										25
									
								
								mgrctl/settings/api.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								mgrctl/settings/api.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | |||||||
|  | from requests.packages import urllib3 | ||||||
|  | from mgrctl.settings.platform import ( | ||||||
|  |     PLATFORM_TYPE, | ||||||
|  |     PLATFORM_VERIFY_SSL_WARNING | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | # Name of nginx container: | ||||||
|  | INPUT_HOSTNAME = 'input' if PLATFORM_TYPE == 'vm' else 'dci_input_1' | ||||||
|  | 
 | ||||||
|  | # Port that nginx container is listening: | ||||||
|  | INPUT_PORT = '1500' | ||||||
|  | 
 | ||||||
|  | # Internal API url: | ||||||
|  | INPUT_URL = f'http://{INPUT_HOSTNAME}:{INPUT_PORT}' | ||||||
|  | 
 | ||||||
|  | # Headers for internal auth: | ||||||
|  | HEADERS = {"Internal-Auth": "on", "Accept": "application/json"} | ||||||
|  | 
 | ||||||
|  | # Suppress warning from urllib3: | ||||||
|  | if not PLATFORM_VERIFY_SSL_WARNING: | ||||||
|  |     # ! This is not recommended, | ||||||
|  |     # ! the user will not see a message about an untrusted SSL connection | ||||||
|  |     urllib3.disable_warnings( | ||||||
|  |         category=urllib3.exceptions.InsecureRequestWarning | ||||||
|  |     ) | ||||||
| @ -1,5 +1,5 @@ | |||||||
| from settings.environment import env | from mgrctl.settings.environment import env | ||||||
| from settings.platform import PLATFORM_CONFIG | from mgrctl.settings.platform import PLATFORM_CONFIG | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # ! Required because some instance use psql db: | # ! Required because some instance use psql db: | ||||||
| @ -6,10 +6,9 @@ BASE_DIR = pathlib.Path(__file__).resolve().parent.parent | |||||||
| 
 | 
 | ||||||
| INSTALLED_APPS = { | INSTALLED_APPS = { | ||||||
|     'vm6': { |     'vm6': { | ||||||
|         'access': 'apps.vm6.access.commands.cli', |         'auth': 'mgrctl.apps.vm6.auth.commands.cli', | ||||||
|         'nodes': 'apps.vm6.nodes.commands.cli', |  | ||||||
|     }, |     }, | ||||||
|     'dci6': { |     'dci6': { | ||||||
|         'access': 'apps.dci6.access.commands.cli', |         'auth': 'mgrctl.apps.dci6.auth.commands.cli', | ||||||
|     }, |     }, | ||||||
| } | } | ||||||
							
								
								
									
										33
									
								
								mgrctl/settings/platform.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								mgrctl/settings/platform.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | |||||||
|  | from mgrctl.settings.environment import env | ||||||
|  | from mgrctl.utils.helpers import parse_json_file | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | PLATFORM_TYPE = env.str('PLATFORM_TYPE', 'vm') | ||||||
|  | 
 | ||||||
|  | PLATFORM_VERIFY_SSL = env.bool('PLATFORM_VERIFY_SSL', True) | ||||||
|  | PLATFORM_VERIFY_SSL_WARNING = env.bool('PLATFORM_VERIFY_SSL_WARNING', True) | ||||||
|  | 
 | ||||||
|  | PLATFORM_CONFIG = env.str( | ||||||
|  |     'PLATFORM_CONFIG', | ||||||
|  |     f'/opt/ispsystem/{PLATFORM_TYPE}/config.json' | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | PLATFORM_CONFIG = parse_json_file(PLATFORM_CONFIG) | ||||||
|  | 
 | ||||||
|  | PLATFORM_URL = env.str( | ||||||
|  |     'PLATFORM_URL', | ||||||
|  |     f"https://{PLATFORM_CONFIG.get('DomainName' ,'replace.me')}" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | # Development mode: | ||||||
|  | PLATFORM_DUMMY = env.bool('PLATFORM_DUMMY', False) | ||||||
|  | 
 | ||||||
|  | PLATFORM_DUMMY_VM6_API_URL = env.str('PLATFORM_DUMMY_VM6_API_URL', '') | ||||||
|  | PLATFORM_DUMMY_VM6_EMAIL = env.str('PLATFORM_DUMMY_VM6_EMAIL', '') | ||||||
|  | PLATFORM_DUMMY_VM6_PASSWORD = env.str('PLATFORM_DUMMY_VM6_PASSWORD', '') | ||||||
|  | PLATFORM_DUMMY_VM6_TOKEN = env.str('PLATFORM_DUMMY_VM6_TOKEN', '') | ||||||
|  | 
 | ||||||
|  | PLATFORM_DUMMY_DCI6_API_URL = env.str('PLATFORM_DUMMY_DCI6_API_URL', '') | ||||||
|  | PLATFORM_DUMMY_DCI6_EMAIL = env.str('PLATFORM_DUMMY_DCI6_EMAIL', '') | ||||||
|  | PLATFORM_DUMMY_DCI6_PASSWORD = env.str('PLATFORM_DUMMY_DCI6_PASSWORD', '') | ||||||
|  | PLATFORM_DUMMY_DCI6_TOKEN = env.str('PLATFORM_DUMMY_DCI6_TOKEN', '') | ||||||
							
								
								
									
										74
									
								
								mgrctl/utils/api_users.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								mgrctl/utils/api_users.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,74 @@ | |||||||
|  | import click | ||||||
|  | from tabulate import tabulate | ||||||
|  | 
 | ||||||
|  | from mgrctl.settings.platform import PLATFORM_URL | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class UserAPI(object): | ||||||
|  |     def __init__(self, callback_class): | ||||||
|  |         """Announces required parameters""" | ||||||
|  |         self.callback_class = callback_class | ||||||
|  |         self.callback = callback_class() | ||||||
|  | 
 | ||||||
|  |     def get_users(self, role: str) -> dict: | ||||||
|  |         data = {} | ||||||
|  |         if role == 'admin': | ||||||
|  |             data = {"where": "((roles+CP+'%@admin%')+AND+(state+EQ+'active'))"} | ||||||
|  |         return self.callback.call_api( | ||||||
|  |             url='/user', | ||||||
|  |             method='GET', | ||||||
|  |             data=data | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |     def _format_users(self, users: dict) -> list: | ||||||
|  |         output = [] | ||||||
|  |         for user in users.get('list', []): | ||||||
|  |             output.append({ | ||||||
|  |                 'id': user.get('id', ''), | ||||||
|  |                 'email': user.get('email', ''), | ||||||
|  |                 'roles': user.get('roles', []), | ||||||
|  |                 'state': user.get('state', '') | ||||||
|  |             }) | ||||||
|  |         return output | ||||||
|  | 
 | ||||||
|  |     def get_first_random_admin(self): | ||||||
|  |         users = self.get_users(role='admin') | ||||||
|  |         admin = {} | ||||||
|  |         for user in users.get('list', []): | ||||||
|  |             if '@admin' in admin.get('roles', []): | ||||||
|  |                 admin = user | ||||||
|  |                 break | ||||||
|  |         return admin | ||||||
|  | 
 | ||||||
|  |     def echo_users(self, role: str) -> None: | ||||||
|  |         users = self.get_users(role) | ||||||
|  |         output = self._format_users(users) | ||||||
|  |         click.echo(tabulate(output, headers='keys')) | ||||||
|  | 
 | ||||||
|  |     def get_access_keys(self, user, count=1): | ||||||
|  |         keys = [] | ||||||
|  |         while count >= 1: | ||||||
|  |             count -= 1 | ||||||
|  |             key = self.callback.get_auth_key(user=user) | ||||||
|  |             check = key.get('key', '') | ||||||
|  |             if check: | ||||||
|  |                 keys.append(key) | ||||||
|  |         return keys | ||||||
|  | 
 | ||||||
|  |     def gen_access_links(self, keys: list) -> list: | ||||||
|  |         links = [] | ||||||
|  |         for key in keys: | ||||||
|  |             _id = key.get('id', '') | ||||||
|  |             link = f"{PLATFORM_URL}/auth/key/{key.get('key', '')}" | ||||||
|  |             links.append({'id': _id, 'link': link}) | ||||||
|  |         return links | ||||||
|  | 
 | ||||||
|  |     def echo_access_links(self, links: list) -> None: | ||||||
|  |         click.echo(tabulate(links, headers='keys')) | ||||||
|  | 
 | ||||||
|  |     def gen_api_token(self, email=None, password=None): | ||||||
|  |         token = self.callback.get_auth_token(email, password) | ||||||
|  |         return token | ||||||
|  | 
 | ||||||
|  |     def echo_api_token(self, token: dict) -> None: | ||||||
|  |         click.echo(tabulate([token], headers='keys')) | ||||||
| @ -1,8 +1,9 @@ | |||||||
| import json | import json | ||||||
| import sys | import sys | ||||||
|  | import click | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def parse_json_file(file_path):  | def parse_json_file(file_path: str) -> dict: | ||||||
|     """ |     """ | ||||||
|     Function read json file as usual config.json then parse it to python dict |     Function read json file as usual config.json then parse it to python dict | ||||||
| 
 | 
 | ||||||
| @ -16,5 +17,7 @@ def parse_json_file(file_path): | |||||||
|         with open(file_path, 'r') as f: |         with open(file_path, 'r') as f: | ||||||
|             return json.load(f) |             return json.load(f) | ||||||
|     except Exception as error: |     except Exception as error: | ||||||
|         print(error) |         click.echo(error) | ||||||
|  |         click.echo("Required: /opt/ispsystem/PLATFORM_TYPE/config.json") | ||||||
|  |         click.echo("Note: don't forget to mount this file into the container") | ||||||
|         sys.exit(1) |         sys.exit(1) | ||||||
							
								
								
									
										27
									
								
								poetry.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										27
									
								
								poetry.lock
									
									
									
										generated
									
									
									
								
							| @ -1066,6 +1066,17 @@ files = [ | |||||||
| cryptography = ">=2.0" | cryptography = ">=2.0" | ||||||
| jeepney = ">=0.6" | jeepney = ">=0.6" | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "sh" | ||||||
|  | version = "2.0.7" | ||||||
|  | description = "Python subprocess replacement" | ||||||
|  | optional = false | ||||||
|  | python-versions = "<4.0,>=3.8.1" | ||||||
|  | files = [ | ||||||
|  |     {file = "sh-2.0.7-py3-none-any.whl", hash = "sha256:2f2f79a65abd00696cf2e9ad26508cf8abb6dba5745f40255f1c0ded2876926d"}, | ||||||
|  |     {file = "sh-2.0.7.tar.gz", hash = "sha256:029d45198902bfb967391eccfd13a88d92f7cebd200411e93f99ebacc6afbb35"}, | ||||||
|  | ] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "shellingham" | name = "shellingham" | ||||||
| version = "1.5.4" | version = "1.5.4" | ||||||
| @ -1077,6 +1088,20 @@ files = [ | |||||||
|     {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, |     {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "tabulate" | ||||||
|  | version = "0.9.0" | ||||||
|  | description = "Pretty-print tabular data" | ||||||
|  | optional = false | ||||||
|  | python-versions = ">=3.7" | ||||||
|  | files = [ | ||||||
|  |     {file = "tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"}, | ||||||
|  |     {file = "tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c"}, | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [package.extras] | ||||||
|  | widechars = ["wcwidth"] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "tomlkit" | name = "tomlkit" | ||||||
| version = "0.12.3" | version = "0.12.3" | ||||||
| @ -1238,4 +1263,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p | |||||||
| [metadata] | [metadata] | ||||||
| lock-version = "2.0" | lock-version = "2.0" | ||||||
| python-versions = "^3.11" | python-versions = "^3.11" | ||||||
| content-hash = "8c1b8d4cae2524776d0d04253f6067ca4a2282d0681677df78afbc5437b0dea5" | content-hash = "ae5af366753982ef73f90fc9f4d59b03db4fb597e31bd88f445423837288f3e1" | ||||||
|  | |||||||
| @ -1,8 +1,13 @@ | |||||||
| [tool.poetry] | [tool.poetry] | ||||||
| name = "isp-maintenance" | name = "mgrctl" | ||||||
| version = "0.1.0" | version = "0.1.0" | ||||||
| description = "Maintenance service for ISPsystem platforms" | description = "Maintenance service for ISPsystem platforms" | ||||||
| authors = ["MOIS3Y <s.zhukovskii@ispsystem.com>", "Failak3 <v.shmidt@ispsystem.com>", "a.garaev <a.garaev@ispsystem.com>", "Ann_M <a.moskovkina@ispsystem.com>"] | authors = [ | ||||||
|  |     "MOIS3Y <s.zhukovskii@ispsystem.com>", | ||||||
|  |     "Failak3 <v.shmidt@ispsystem.com>", | ||||||
|  |     "a.garaev <a.garaev@ispsystem.com>", | ||||||
|  |     "Ann_M <a.moskovkina@ispsystem.com>" | ||||||
|  | ] | ||||||
| license = "MIT" | license = "MIT" | ||||||
| readme = "README.md" | readme = "README.md" | ||||||
| 
 | 
 | ||||||
| @ -14,11 +19,15 @@ requests = "^2.31.0" | |||||||
| environs = "^10.3.0" | environs = "^10.3.0" | ||||||
| pymysql = {extras = ["rsa"], version = "^1.1.0"} | pymysql = {extras = ["rsa"], version = "^1.1.0"} | ||||||
| poetry-plugin-export = "^1.6.0" | poetry-plugin-export = "^1.6.0" | ||||||
|  | sh = "^2.0.7" | ||||||
|  | tabulate = "^0.9.0" | ||||||
| 
 | 
 | ||||||
| [tool.poetry.group.dev.dependencies] | [tool.poetry.group.dev.dependencies] | ||||||
| flake8 = "^7.0.0" | flake8 = "^7.0.0" | ||||||
| 
 | 
 | ||||||
|  | [tool.poetry.scripts] | ||||||
|  | mgrctl = 'mgrctl.mgrctl:cli' | ||||||
|  | 
 | ||||||
| [build-system] | [build-system] | ||||||
| requires = ["poetry-core"] | requires = ["poetry-core"] | ||||||
| build-backend = "poetry.core.masonry.api" | build-backend = "poetry.core.masonry.api" | ||||||
| 
 |  | ||||||
|  | |||||||
| @ -500,9 +500,15 @@ requests==2.31.0 ; python_version >= "3.11" and python_version < "4.0" \ | |||||||
| secretstorage==3.3.3 ; python_version >= "3.11" and python_version < "4.0" and sys_platform == "linux" \ | secretstorage==3.3.3 ; python_version >= "3.11" and python_version < "4.0" and sys_platform == "linux" \ | ||||||
|     --hash=sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77 \ |     --hash=sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77 \ | ||||||
|     --hash=sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99 |     --hash=sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99 | ||||||
|  | sh==2.0.7 ; python_version >= "3.11" and python_version < "4.0" \ | ||||||
|  |     --hash=sha256:029d45198902bfb967391eccfd13a88d92f7cebd200411e93f99ebacc6afbb35 \ | ||||||
|  |     --hash=sha256:2f2f79a65abd00696cf2e9ad26508cf8abb6dba5745f40255f1c0ded2876926d | ||||||
| shellingham==1.5.4 ; python_version >= "3.11" and python_version < "4.0" \ | shellingham==1.5.4 ; python_version >= "3.11" and python_version < "4.0" \ | ||||||
|     --hash=sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686 \ |     --hash=sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686 \ | ||||||
|     --hash=sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de |     --hash=sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de | ||||||
|  | tabulate==0.9.0 ; python_version >= "3.11" and python_version < "4.0" \ | ||||||
|  |     --hash=sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c \ | ||||||
|  |     --hash=sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f | ||||||
| tomlkit==0.12.3 ; python_version >= "3.11" and python_version < "4.0" \ | tomlkit==0.12.3 ; python_version >= "3.11" and python_version < "4.0" \ | ||||||
|     --hash=sha256:75baf5012d06501f07bee5bf8e801b9f343e7aac5a92581f20f80ce632e6b5a4 \ |     --hash=sha256:75baf5012d06501f07bee5bf8e801b9f343e7aac5a92581f20f80ce632e6b5a4 \ | ||||||
|     --hash=sha256:b0a645a9156dc7cb5d3a1f0d4bab66db287fcb8e0430bdd4664a095ea16414ba |     --hash=sha256:b0a645a9156dc7cb5d3a1f0d4bab66db287fcb8e0430bdd4664a095ea16414ba | ||||||
|  | |||||||
							
								
								
									
										10
									
								
								scripts/devtools/cli/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								scripts/devtools/cli/__init__.py
									
									
									
									
									
										Normal 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" | ||||||
							
								
								
									
										50
									
								
								scripts/devtools/cli/builder.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								scripts/devtools/cli/builder.py
									
									
									
									
									
										Normal 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' | ||||||
|  | ) | ||||||
							
								
								
									
										39
									
								
								scripts/devtools/cli/lazy_group.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								scripts/devtools/cli/lazy_group.py
									
									
									
									
									
										Normal 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 | ||||||
							
								
								
									
										57
									
								
								scripts/devtools/cli/runner.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								scripts/devtools/cli/runner.py
									
									
									
									
									
										Normal 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' | ||||||
|  | ) | ||||||
							
								
								
									
										18
									
								
								scripts/devtools/cli/settings.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								scripts/devtools/cli/settings.py
									
									
									
									
									
										Normal 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) | ||||||
							
								
								
									
										15
									
								
								scripts/devtools/cli/utils.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								scripts/devtools/cli/utils.py
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										30
									
								
								scripts/devtools/dev.py
									
									
									
									
									
										Executable 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() | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user