diff --git a/backend/build/deps b/backend/build/deps new file mode 100644 index 0000000000000000000000000000000000000000..921b06cde9047b3f0bd142b4bfc54f202af585d9 --- /dev/null +++ b/backend/build/deps @@ -0,0 +1,16 @@ +mariadb-server # mariadb 数据库服务端 +expect # 启动服务脚本需要 expect 命令 +oedp # +dnf-plugins-core # 工具需要 repoquery 用于查询所有 mcp 服务包 + +python3 # +python3-mysqlclient # 连接 mariadb +python3-concurrent-log-handler # 日志 +python3-cryptography # 自定义加解密需要 +python3-Django # Web 框架 +python3-django-rest-framework # (暂无) Web 框架 +python3-pyyaml # 处理 yaml 文件 +python3-psutil # 查询进程信息 + +# python 相关包 +djangorestframework \ No newline at end of file diff --git a/backend/configs/mariadb/init_mariadb.conf b/backend/configs/mariadb/init_mariadb.conf new file mode 100644 index 0000000000000000000000000000000000000000..41e400e5ff9c20e894c734cade7ee9e399496317 --- /dev/null +++ b/backend/configs/mariadb/init_mariadb.conf @@ -0,0 +1,3 @@ +root_password = +# dev_store 用户的密码至少包含8个字符,大小写字母、数字、特殊符号三种以上 +dev_store_password = \ No newline at end of file diff --git a/backend/configs/mariadb/mariadb.conf b/backend/configs/mariadb/mariadb.conf new file mode 100644 index 0000000000000000000000000000000000000000..ceeae2d017e5f92ce02d86c57b4916e3b96b935f --- /dev/null +++ b/backend/configs/mariadb/mariadb.conf @@ -0,0 +1,9 @@ +[mariadb] +# 数据库名称 +name = +# 数据库地址 +host = 127.0.0.1 +# 端口 +port = 3306 +# 数据库用户名 +user = dev_store \ No newline at end of file diff --git a/backend/configs/mariadb/mariadb_ciphertext_data.json b/backend/configs/mariadb/mariadb_ciphertext_data.json new file mode 100644 index 0000000000000000000000000000000000000000..d1d8ef9529827ff855de0d6ebd1df21dc4069510 --- /dev/null +++ b/backend/configs/mariadb/mariadb_ciphertext_data.json @@ -0,0 +1,7 @@ +{ + "half_key": "", + "encrypted_work_key": "", + "work_key_iv": "", + "plaintext_iv": "", + "ciphertext": "" +} \ No newline at end of file diff --git a/backend/configs/mcp.repo b/backend/configs/mcp.repo new file mode 100644 index 0000000000000000000000000000000000000000..af3884a4eef663134711aafc22787eac4676b280 --- /dev/null +++ b/backend/configs/mcp.repo @@ -0,0 +1,4 @@ +[mcp] +name=mcp +baseurl=https://eulermaker.compass-ci.openeuler.openatom.cn/api/ems4/repositories/mcps-repo/openEuler%3A24.03-LTS-SP2/$basearch/ +enabled=1 \ No newline at end of file diff --git a/backend/configs/task_scheduler.conf b/backend/configs/task_scheduler.conf new file mode 100644 index 0000000000000000000000000000000000000000..b5792e86dce97e2a0b588ca1fd604e3c8a03e5c0 --- /dev/null +++ b/backend/configs/task_scheduler.conf @@ -0,0 +1,2 @@ +[scheduler] +max_concurrency = 10 \ No newline at end of file diff --git a/backend/dev_store/__init__.py b/backend/dev_store/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/backend/dev_store/asgi.py b/backend/dev_store/asgi.py new file mode 100644 index 0000000000000000000000000000000000000000..181391da30bb96afea0cdd032d6d06628d83ef13 --- /dev/null +++ b/backend/dev_store/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for dev_store 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/5.2/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'dev_store.settings') + +application = get_asgi_application() diff --git a/backend/dev_store/settings.py b/backend/dev_store/settings.py new file mode 100644 index 0000000000000000000000000000000000000000..63f04e4afa95de4dc15b124b9d98956eb05741ea --- /dev/null +++ b/backend/dev_store/settings.py @@ -0,0 +1,132 @@ +""" +Django settings for dev_store project. + +Generated by 'django-admin startproject' using Django 5.2.3. + +For more information on this file, see +https://docs.djangoproject.com/en/5.2/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/5.2/ref/settings/ +""" + +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +from constants.configs.mariadb_config import get_settings_mariadb_config +from utils.time import get_time_zone + +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'django-insecure-&7)18d*hbf$co$s8jx5@)hxy-+$_)=6)r&eyy#1jq^*m479e10' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True +APPEND_SLASH = 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', + 'artifacts.apps.ArtifactsConfig', + 'tasks.apps.TasksConfig' +] + +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 = 'dev_store.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'dev_store.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/5.2/ref/settings/#databases + +config_info = get_settings_mariadb_config() +DATABASES = { + 'default': config_info +} + + +# Password validation +# https://docs.djangoproject.com/en/5.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/5.2/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = get_time_zone() + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/5.2/howto/static-files/ + +STATIC_URL = 'static/' + +# Default primary key field type +# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +# Rest Framework +REST_FRAMEWORK = { + # 分页 + 'DEFAULT_PAGINATION_CLASS': 'utils.pagination.CustomPageNumberPagination', +} diff --git a/backend/dev_store/urls.py b/backend/dev_store/urls.py new file mode 100644 index 0000000000000000000000000000000000000000..bc88cfb5f7a8ee6a91a96151bdd415815b975678 --- /dev/null +++ b/backend/dev_store/urls.py @@ -0,0 +1,29 @@ +""" +URL configuration for dev_store project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/5.2/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path, include +from rest_framework import routers + +from artifacts.views import ArtifactViewSet + +router = routers.DefaultRouter() +router.register(r'v1.0/artifacts', ArtifactViewSet, basename='artifacts') + +urlpatterns = [ + path('admin/', admin.site.urls), + path('', include(router.urls)), +] diff --git a/backend/dev_store/wsgi.py b/backend/dev_store/wsgi.py new file mode 100644 index 0000000000000000000000000000000000000000..f45679abd87c98393c8bc7d516063fbcf1c35787 --- /dev/null +++ b/backend/dev_store/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for dev_store 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/5.2/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'dev_store.settings') + +application = get_wsgi_application() diff --git a/backend/manage.py b/backend/manage.py new file mode 100644 index 0000000000000000000000000000000000000000..56aa4b9496ce5ec0b685aadc22b5f59979067604 --- /dev/null +++ b/backend/manage.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# oeDeploy is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# http://license.coscl.org.cn/MulanPSL2 +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR +# PURPOSE. +# See the Mulan PSL v2 for more details. +# Create: 2025-07-18 +# ====================================================================================================================== + +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'dev_store.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/backend/services/encrypt_mariadb_passwd.py b/backend/services/encrypt_mariadb_passwd.py new file mode 100644 index 0000000000000000000000000000000000000000..6bf2f0d77f871b9373868345939030fec5213c63 --- /dev/null +++ b/backend/services/encrypt_mariadb_passwd.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# oeDeploy is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# http://license.coscl.org.cn/MulanPSL2 +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR +# PURPOSE. +# See the Mulan PSL v2 for more details. +# Create: 2025-07-18 +# ====================================================================================================================== + +import sys + +if "/var/lib/dev-store/src" not in sys.path: + sys.path.append("/var/lib/dev-store/src") + +from constants.paths import MARIADB_JSON_FILE +from utils.cipher import CustomCipher +from utils.file_handler.json_handler import JSONHandler + + +if __name__ == '__main__': + try: + plaintext = sys.argv[1] + custom_cipher = CustomCipher() + ciphertext_data = custom_cipher.encrypt_plaintext(plaintext) + json_handler = JSONHandler(file_path=MARIADB_JSON_FILE, should_print=True) + json_handler.data.update(ciphertext_data) + json_handler.save() + except Exception as ex: + print(ex) + sys.exit(1) diff --git a/backend/services/init_mariadb.sh b/backend/services/init_mariadb.sh new file mode 100644 index 0000000000000000000000000000000000000000..8e555f5c6ef81d9b9bf94b05848fbc057d5b2df2 --- /dev/null +++ b/backend/services/init_mariadb.sh @@ -0,0 +1,340 @@ +#!/bin/bash +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# oeDeploy is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# http://license.coscl.org.cn/MulanPSL2 +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR +# PURPOSE. +# See the Mulan PSL v2 for more details. +# Create: 2025-07-18 +# ====================================================================================================================== + +auto=$1 +CONFIG_DIR="/etc/dev-store/mariadb" +INIT_MARIADB_CONFIG_FILE="${CONFIG_DIR}/init_mariadb.conf" +SERVICES_DIR="/var/lib/dev-store/services" + +CURRENT_DIR=$(pwd) +source ${CURRENT_DIR}/log.sh + +# 读取配置文件 +function read_config_value { + local key="$1" + + # 判断配置文件中 key 是否存在 + local item=$(grep "^${key} =" "${INIT_MARIADB_CONFIG_FILE}") + if [[ -z "${item}" ]]; then + error "The key '${key}' not found in the configuration file ${INIT_MARIADB_CONFIG_FILE}" + exit 1 + fi + + # 判断配置文件中对应 key 的值是否存在 + local value=$(echo "${item}" | awk -F= '{print $2}' | sed 's/[[:space:]]*$//' | xargs) + + if [[ -n "${value}" ]]; then + echo "${value}" + else + error "The value of key '${key}' is empty in the configuration file ${INIT_MARIADB_CONFIG_FILE}" + exit 1 + fi +} + +# 检查密码复杂度,密码至少包含8个字符,大小写字母、数字、特殊符号三种以上 +function check_password_complexity() +{ + local variable_content=$1 + local complexity=0 + + if [[ ${#variable_content} -ge 8 ]]; then + complexity=$((${complexity}+1)) + else + return 1 + fi + + if [[ "${variable_content}" =~ [[:upper:]] ]]; then + complexity=$((${complexity}+1)) + fi + + if [[ "${variable_content}" =~ [[:lower:]] ]]; then + complexity=$((${complexity}+1)) + fi + + if [[ "${variable_content}" =~ [[:digit:]] ]]; then + complexity=$((${complexity}+1)) + fi + + if [[ "${variable_content}" =~ [[:punct:]] ]]; then + complexity=$((${complexity}+1)) + fi + + unset variable_content + if [[ "${complexity}" -ge 4 ]]; then + return 0 + else + return 1 + fi +} + + +# 配置MariaDB服务 +function configure_mariadb() +{ + local auto=$1 + local Y_N + + # 交互式执行会询问 MariaDB 是否已被配置过,自动执行默认 MariaDB 没有被配置过 + if [ "${auto}" == "auto" ]; then + Y_N="n" + else + read -p "Whether MariaDB is configured? [Y/n] (default: n) " Y_N + fi + # 判断 MariaDB 是否已被配置过,若已被配置过则跳过,若没有则开始配置 + if [[ "${Y_N}" == "y" || "${Y_N}" == "Y" ]]; then + return + elif [[ ! -n "${Y_N}" || "${Y_N}" == "N" || "${Y_N}" == "n" ]]; then + # 启动 MariaDB 服务 + info "Starting the MariaDB service." + systemctl start mariadb + if [[ $? -ne 0 ]]; then + error "Failed to start the MariaDB service." + exit 1 + fi + # 检查服务是否启动 + mariadb_status=$(systemctl is-active mariadb) + if [[ "${mariadb_status}" == "active" ]]; then + info "The MariaDB service is active." + else + error "The MariaDB service is inactive." + exit 1 + fi + # 设置为开机自启动服务 + systemctl enable mariadb + if [[ $? -ne 0 ]]; then + warn "Failed to enable the MariaDB service." + fi + + # 检查防火墙是否启动,如果启动则检查 3306 端口是否在防火墙白名单中,如果不存在则添加到白名单中 + info "Start to check firewall." + if systemctl is-active --quiet firewalld; then + port_3306=$(firewall-cmd --query-port=3306/tcp) + if [[ "${port_3306}" == "no" ]]; then + port_3306=$(firewall-cmd --zone=public --add-port=3306/tcp --permanent) + firewall-cmd --reload + fi + port_3306=$(firewall-cmd --query-port=3306/tcp) + if [[ "${port_3306}" != "yes" ]]; then + error "Failed to enable port 3306." + exit 1 + fi + fi + info "Check firewall done." + + # 执行 mysql_secure_installation,进行 MariaDB 的安全配置 + info "Execute the command [mysql_secure_installation] to perform MariaDB security configuration." + if [ "${auto}" == "auto" ]; then + default_root_pw="\n" + switch_unix_socket="n" + set_root_pw="y" + root_password="$(read_config_value 'root_password')" + change_root_pw="n" + remove_anonymous_users="y" + disallow_root_login_remotely="n" + remove_test_database_and_access_to_it="y" + reload_privilege_tables="y" + # 首次安装,mariadb 的 root 密码为空,需要设置 root 密码 + input_string="${default_root_pw}" + input_string+="${switch_unix_socket}\n" + input_string+="${set_root_pw}\n" + input_string+="${root_password}\n" + input_string+="${root_password}\n" + input_string+="${remove_anonymous_users}\n" + input_string+="${disallow_root_login_remotely}\n" + input_string+="${remove_test_database_and_access_to_it}\n" + input_string+="${reload_privilege_tables}\n" + expect -c " +set timeout 5 +spawn mysql_secure_installation +expect \"Enter current password for root (enter for none):\" +send \"${input_string}\" +expect { + \"*Thanks for using MariaDB!*\" { + exit 0 + } + default { + exit 1 + } +} +" + return_code=$? + if [[ "${return_code}" == "1" ]]; then + echo "" + error "Automatically configuring the mariadb fails, please try to configure manually." + exit 1 + fi + else + mysql_secure_installation + fi + info "Perform MariaDB security configuration successfully." + return + else + error "The input is invalid. Please input again." + exit 1 + fi +} + + +# 检查自定义数据库名字复杂度,自定义数据库名字至少包含2个字符,大小写字母、下划线、数字两种以上 +function check_database_name() +{ + local variable_content=$1 + local complexity=0 + + if [[ "${variable_content}" =~ [[:upper:]] ]]; then + complexity=$((${complexity}+1)) + fi + + if [[ "${variable_content}" =~ [[:lower:]] ]]; then + complexity=$((${complexity}+1)) + fi + + if [[ "${variable_content}" =~ [[:digit:]] ]]; then + complexity=$((${complexity}+1)) + fi + + if [[ "${variable_content}" =~ "_" ]]; then + complexity=$((${complexity}+1)) + fi + # 包含 a-zA-Z0-9_ 之外的字符都不符合要求 + if [[ "${variable_content}" =~ [^a-zA-Z0-9_] ]]; then + complexity=0 + fi + + unset variable_content + if [[ ${complexity} -ge 2 ]]; then + return 0 + else + return 1 + fi +} + +info "Start to configure MariaDB for dev-store." +configure_mariadb "${auto}" +unset Y_N + +# 输入或获取 dev_store 密码,并检查其复杂度是否符合要求 +if [ "${auto}" == "auto" ]; then + dev_store_passwd=$(read_config_value "dev_store_password") + check_password_complexity ${dev_store_passwd} + if [[ $? -ne 0 ]]; then + error "The password must contain at least eight characters, including uppercase lowercase digits and special characters." + error "The password of the dev_store user for MariaDB is invalid. Please change the value of dev_store_password in the ${INIT_MARIADB_CONFIG_FILE}." + exit 1 + fi +else + stty -echo + while true + do + should_break=false + for i in {1..5}; do + read -p "Enter the password of dev_store user for MariaDB: " dev_store_passwd_01 + echo "" + read -p "Confirm: " dev_store_passwd_02 + echo "" + if [[ "${dev_store_passwd_01}" == "${dev_store_passwd_02}" ]]; then + should_break=true + break + fi + error "The provided passwords do not match. Please re-enter them for verification." + done + if [ ! ${should_break} ]; then + stty echo + exit 1 + fi + dev_store_passwd=${dev_store_passwd_01} + check_password_complexity ${dev_store_passwd} + if [[ $? -ne 0 ]]; then + error "The password must contain at least eight characters, including uppercase lowercase digits and special characters." + error "The password of the dev_store user for MariaDB is invalid. Please input again." + else + break + fi + done + stty echo +fi + +# 获取自定义数据库名 +while true +do + warn "If the database name already exists, it will be overwritten." + if [ "${auto}" == "auto" ]; then + Y_N="Y" + else + read -p "Use default dev_store_db database? [Y/n] (default: Y) " Y_N + fi + # 使用默认 + if [[ ! -n "${Y_N}" || "${Y_N}" == "y" || "${Y_N}" == "Y" ]]; then + mariadb_name=dev_store_db + break + elif [[ "${Y_N}" == "N" || "${Y_N}" == "n" ]]; then + # 用户自定义数据库 + read -p "Please input the name of the database to be created: " mariadb_name + check_database_name ${mariadb_name} + if [[ $? -ne 0 ]]; then + error "The database name must contain at least two types of characters, including uppercase lowercase underscores and digits." + error "The input database name entered is invalid. Please input again." + else + break + fi + else + error "The input is invalid. Please input again." + fi +done +unset Y_N + +# 创建用户 dev_store 以及自定义名称的数据库 +if [ "${auto}" == "auto" ]; then + root_password=$(read_config_value "root_password") +else + stty -echo + read -p "Enter the password of the root user of the MariaDB again: " root_password + echo "" + stty echo +fi +info "Start to create user dev_store and database ${mariadb_name}." +mysql -uroot -p${root_password} << EOF +DROP DATABASE IF EXISTS ${mariadb_name}; +CREATE DATABASE IF NOT EXISTS ${mariadb_name} CHARACTER SET utf8 COLLATE utf8_bin; + +DELETE FROM mysql.user WHERE User='dev_store'; +DELETE FROM mysql.db WHERE User='dev_store'; +flush privileges; +# dev_store 用户权限仅限操作自定义新创建的数据库 +CREATE USER 'dev_store'@'localhost' IDENTIFIED BY '${dev_store_passwd}'; +GRANT ALL ON ${mariadb_name}.* TO 'dev_store'@'localhost' IDENTIFIED BY '${dev_store_passwd}' WITH GRANT OPTION; +flush privileges; +EOF +if [[ $? -ne 0 ]]; then + error "Failed to create user dev_store and database ${mariadb_name}." + exit 1 +fi +info "Create user dev_store and database ${mariadb_name} successfully." + +unset root_password + +# 更新 mariadb.conf 和加密 dev_store 用户的密码 +python3 "${SERVICES_DIR}/modify_mariadb_config.py" ${mariadb_name} +if [[ $? -ne 0 ]]; then + error "Failed to update ${CONFIG_DIR}/mariadb.conf." + exit 1 +fi +python3 "${SERVICES_DIR}/encrypt_mariadb_passwd.py" ${dev_store_passwd} +if [[ $? -ne 0 ]]; then + error "Failed to encrypt password of user dev_store." + exit 1 +fi + +unset dev_store_passwd + +info "MariaDB is configured successfully." \ No newline at end of file diff --git a/backend/services/log.sh b/backend/services/log.sh new file mode 100644 index 0000000000000000000000000000000000000000..f096676385f95a83c412b4073c53348ca5473028 --- /dev/null +++ b/backend/services/log.sh @@ -0,0 +1,106 @@ +#!/bin/bash +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# oeDeploy is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# http://license.coscl.org.cn/MulanPSL2 +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR +# PURPOSE. +# See the Mulan PSL v2 for more details. +# Create: 2025-07-18 +# ====================================================================================================================== + +# 日志模块 - 默认配置 +# 默认日志级别 (DEBUG, INFO, WARN, ERROR, FATAL) +LOG_LEVEL="INFO" +# 日志目录 +LOG_DIR="/var/log/dev-store/init-services" +# 日志文件名 +LOG_FILE="$(date "+%Y%m%d%H%M%S%1N").log" +# 日志文件最大大小 (10MB) +MAX_LOG_SIZE=10485760 + +# 检查并创建日志目录 +mkdir -p "${LOG_DIR}" + +# 日志级别颜色定义 +declare -A LOG_COLORS=( + ["DEBUG"]="\033[0;36m" # 青色 + ["INFO"]="\033[0;32m" # 绿色 + ["WARN"]="\033[0;33m" # 黄色 + ["ERROR"]="\033[0;31m" # 红色 +) +LOG_RESET="\033[0m" # 重置颜色 + +# 日志级别权重(用于比较) +declare -A LOG_WEIGHTS=( + ["DEBUG"]=10 + ["INFO"]=20 + ["WARN"]=30 + ["ERROR"]=40 +) + +# 检查当前日志级别是否足够输出 +should_log() { + local msg_level="$1" + [[ ${LOG_WEIGHTS[${msg_level}]} -ge ${LOG_WEIGHTS[${LOG_LEVEL}]} ]] +} + +# 日志轮转检查 +rotate_logs() { + local log_path="${LOG_DIR}/${LOG_FILE}" + [[ ! -f "${log_path}" ]] && return + local current_size=$(wc -c < "${log_path}") + if [[ ${current_size} -ge ${MAX_LOG_SIZE} ]]; then + local timestamp=$(date +%Y%m%d%H%M%S) + mv "${log_path}" "${LOG_DIR}/${LOG_FILE%.*}_${timestamp}.log" + echo "Log rotated: ${log_path} -> ${LOG_DIR}/${LOG_FILE%.*}_${timestamp}.log" + fi +} + +# 核心日志函数 +log() { + local level="$1" + shift + local message="$*" + if ! should_log "${level}"; then + return + fi + rotate_logs + local timestamp=$(date "+%Y-%m-%d %H:%M:%S.%3N") + local log_entry="[${timestamp}] [${level}] ${message}" + # 输出到终端(带颜色) + if [ -t 1 ]; then + echo -e "${LOG_COLORS[${level}]}${log_entry}${LOG_RESET}" + else + echo "${log_entry}" + fi + # 写入日志文件(不带颜色) + echo "${log_entry}" >> "${LOG_DIR}/${LOG_FILE}" +} + +# 快捷日志函数 +debug() { log "DEBUG" "$@"; } +info() { log "INFO" "$@"; } +warn() { log "WARN" "$@"; } +error() { log "ERROR" "$@"; } +start_info() { + local str="$1" + local str_len=${#str} + local total_len=60 + + # 计算两侧 '=' 的数量 + local equals_len=$(( (total_len - str_len - 2) / 2 )) + + # 生成左侧 '=' 字符串 + local left_equals=$(printf "%${equals_len}s" | tr ' ' '=') + + # 生成右侧 '=' 字符串(可能比左侧多1个字符,以防奇数情况) + local right_equals=$left_equals + if [ $(( (total_len - str_len) % 2 )) -ne 0 ]; then + right_equals+="=" + fi + + log "INFO" "${left_equals} ${str} ${right_equals}" +} \ No newline at end of file diff --git a/backend/services/modify_mariadb_config.py b/backend/services/modify_mariadb_config.py new file mode 100644 index 0000000000000000000000000000000000000000..9925325474fd09cee357bb4de379dd4e7078ee90 --- /dev/null +++ b/backend/services/modify_mariadb_config.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# oeDeploy is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# http://license.coscl.org.cn/MulanPSL2 +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR +# PURPOSE. +# See the Mulan PSL v2 for more details. +# Create: 2025-07-18 +# ====================================================================================================================== + +import sys + +if "/var/lib/dev-store/src" not in sys.path: + sys.path.append("/var/lib/dev-store/src") + +from constants.paths import MARIADB_CONFIG_FILE +from utils.file_handler.conf_handler import ConfHandler + + +if __name__ == '__main__': + try: + database_name = sys.argv[1] + conf_handler = ConfHandler(file_path=MARIADB_CONFIG_FILE, should_print=True) + conf_handler.set('mariadb', 'name', database_name) + conf_handler.save() + except Exception as ex: + print(ex) + sys.exit(1) diff --git a/backend/sync_files.sh b/backend/sync_files.sh new file mode 100644 index 0000000000000000000000000000000000000000..494ca07313c9543af256e1e436496977444c65c6 --- /dev/null +++ b/backend/sync_files.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# Copyright (c) 2025 Huawei Technologies Co., Ltd. +# oeDeploy is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# http://license.coscl.org.cn/MulanPSL2 +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR +# PURPOSE. +# See the Mulan PSL v2 for more details. +# Create: 2025-07-18 +# ====================================================================================================================== + +set -e + +[ ! -d /var/lib/dev-store ] && mkdir -p /var/lib/dev-store +[ ! -d /var/lib/dev-store/src ] && mkdir -p /var/lib/dev-store/src +cp -rf artifacts tasks constants dev_store utils manage.py /var/lib/dev-store/src +cp -rf services /var/lib/dev-store +echo "success $(date "+%Y-%m-%d %H:%M:%S")"