mirror of
https://github.com/Websoft9/websoft9.git
synced 2024-11-21 15:10:22 +00:00
feat: add settings module
This commit is contained in:
parent
709d8a5615
commit
79392a2f70
21 changed files with 187 additions and 29 deletions
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
__pycache__
|
||||
.idea
|
||||
logs
|
||||
.venv
|
||||
.vscode
|
2
Makefile
Normal file
2
Makefile
Normal file
|
@ -0,0 +1,2 @@
|
|||
test:
|
||||
python -m unitest test/settings/test_settings.py
|
0
appmanage/__init__.py
Normal file
0
appmanage/__init__.py
Normal file
0
appmanage/api/exception/__init__.py
Normal file
0
appmanage/api/exception/__init__.py
Normal file
|
@ -2,4 +2,9 @@ class CommandException(Exception):
|
|||
def __init__(self, code, message, detail):
|
||||
self.code = code
|
||||
self.message = message
|
||||
self.detail = detail
|
||||
self.detail = detail
|
||||
|
||||
|
||||
class MissingConfigException(CommandException):
|
||||
|
||||
pass
|
||||
|
|
0
appmanage/api/model/__init__.py
Normal file
0
appmanage/api/model/__init__.py
Normal file
0
appmanage/api/service/__init__.py
Normal file
0
appmanage/api/service/__init__.py
Normal file
0
appmanage/api/settings/__init__.py
Normal file
0
appmanage/api/settings/__init__.py
Normal file
50
appmanage/api/settings/settings.py
Normal file
50
appmanage/api/settings/settings.py
Normal file
|
@ -0,0 +1,50 @@
|
|||
from api.utils.helper import Singleton
|
||||
|
||||
|
||||
__all__ = ['settings']
|
||||
|
||||
|
||||
class Settings(object):
|
||||
|
||||
__metaclass__ = Singleton
|
||||
|
||||
def __init__(self):
|
||||
self._config = {}
|
||||
self.config_file = '/usr/src/app/config/settings.conf'
|
||||
|
||||
def init_config_from_file(self, config_file: str=None):
|
||||
if config_file:
|
||||
self.config_file = config_file
|
||||
try:
|
||||
with open(config_file, 'r') as f:
|
||||
data = f.readlines()
|
||||
except Exception:
|
||||
data = []
|
||||
for i in data:
|
||||
i = i.replace('\n', '').replace('\r\n', '')
|
||||
key, value = i.split('=')
|
||||
if self._config.get(key) != value:
|
||||
self._config[key] = value
|
||||
|
||||
def update_setting(self, key: str, value: str):
|
||||
self._config[key] = value
|
||||
self.flush_config()
|
||||
|
||||
def get_setting(self, key: str, default=None):
|
||||
return self._config.get(key, default)
|
||||
|
||||
def list_all_settings(self) -> list:
|
||||
return self._config
|
||||
|
||||
def delete_setting(self, key: str, value: str):
|
||||
if key in self._config:
|
||||
del self._config[key]
|
||||
|
||||
def flush_config(self):
|
||||
with open(self.config_file, 'w') as f:
|
||||
for key, value in self._config.items():
|
||||
f.write(f'{key}={value}\n')
|
||||
|
||||
|
||||
|
||||
settings = Settings()
|
0
appmanage/api/utils/__init__.py
Normal file
0
appmanage/api/utils/__init__.py
Normal file
|
@ -1,25 +1,26 @@
|
|||
# 所有常量统一定义区
|
||||
|
||||
# 错误代码定义
|
||||
ERROR_CLIENT_PARAM_BLANK="Client.Parameter.Blank.Error"
|
||||
ERROR_CLIENT_PARAM_Format="Client.Parameter.Format.Error"
|
||||
ERROR_CLIENT_PARAM_NOTEXIST="Client.Parameter.Value.NotExist.Error"
|
||||
ERROR_CLIENT_PARAM_REPEAT="Client.Parameter.Value.Repeat.Error"
|
||||
ERROR_CONFIG_NGINX="Nginx.Configure.Error"
|
||||
ERROR_SERVER_COMMAND="Server.Container.Error"
|
||||
ERROR_SERVER_SYSTEM="Server.SystemError"
|
||||
ERROR_SERVER_RESOURCE="Server.ResourceError"
|
||||
ERROR_CLIENT_PARAM_BLANK = "Client.Parameter.Blank.Error"
|
||||
ERROR_CLIENT_PARAM_Format = "Client.Parameter.Format.Error"
|
||||
ERROR_CLIENT_PARAM_NOTEXIST = "Client.Parameter.Value.NotExist.Error"
|
||||
ERROR_CLIENT_PARAM_REPEAT = "Client.Parameter.Value.Repeat.Error"
|
||||
ERROR_CONFIG_NGINX = "Nginx.Configure.Error"
|
||||
ERROR_SERVER_COMMAND = "Server.Container.Error"
|
||||
ERROR_SERVER_SYSTEM = "Server.SystemError"
|
||||
ERROR_SERVER_RESOURCE = "Server.ResourceError"
|
||||
ERROR_SERVER_CONFIG_MISSING = "Server.Config.NotFound"
|
||||
|
||||
# 错误信息定义
|
||||
ERRORMESSAGE_CLIENT_PARAM_BLANK="Client.Parameter.Blank.Error"
|
||||
ERRORMESSAGE_CLIENT_PARAM_Format="Client.Parameter.Format.Error"
|
||||
ERRORMESSAGE_CLIENT_PARAM_NOTEXIST="Client.Parameter.Value.NotExist.Error"
|
||||
ERRORMESSAGE_CLIENT_PARAM_REPEAT="Client.Parameter.Value.Repeat.Error"
|
||||
ERRORMESSAGE_SERVER_COMMAND="Server.Container.Error"
|
||||
ERRORMESSAGE_SERVER_SYSTEM="Server.SystemError"
|
||||
ERRORMESSAGE_SERVER_RESOURCE="Server.ResourceError"
|
||||
ERRORMESSAGE_SERVER_VERSION_NOTSUPPORT="Server.Version.NotSupport"
|
||||
ERRORMESSAGE_SERVER_VERSION_NEEDUPGRADE="Server.Version.NeedUpgradeCore"
|
||||
ERRORMESSAGE_CLIENT_PARAM_BLANK = "Client.Parameter.Blank.Error"
|
||||
ERRORMESSAGE_CLIENT_PARAM_Format = "Client.Parameter.Format.Error"
|
||||
ERRORMESSAGE_CLIENT_PARAM_NOTEXIST = "Client.Parameter.Value.NotExist.Error"
|
||||
ERRORMESSAGE_CLIENT_PARAM_REPEAT = "Client.Parameter.Value.Repeat.Error"
|
||||
ERRORMESSAGE_SERVER_COMMAND = "Server.Container.Error"
|
||||
ERRORMESSAGE_SERVER_SYSTEM = "Server.SystemError"
|
||||
ERRORMESSAGE_SERVER_RESOURCE = "Server.ResourceError"
|
||||
ERRORMESSAGE_SERVER_VERSION_NOTSUPPORT = "Server.Version.NotSupport"
|
||||
ERRORMESSAGE_SERVER_VERSION_NEEDUPGRADE = "Server.Version.NeedUpgradeCore"
|
||||
|
||||
# 应用状态定义
|
||||
# 应用启动中 installing
|
||||
|
@ -33,7 +34,7 @@ APP_STATUS_RESTARTING = "restarting"
|
|||
# 应用错误 failed
|
||||
APP_STATUS_FAILED = "failed"
|
||||
|
||||
NGINX_URL="http://websoft9-nginxproxymanager:81"
|
||||
#ARTIFACT_URL="https://artifact.azureedge.net/release/websoft9"
|
||||
ARTIFACT_URL="https://w9artifact.blob.core.windows.net/release/websoft9"
|
||||
ARTIFACT_URL_DEV="https://w9artifact.blob.core.windows.net/dev/websoft9"
|
||||
NGINX_URL = "http://websoft9-nginxproxymanager:81"
|
||||
# ARTIFACT_URL="https://artifact.azureedge.net/release/websoft9"
|
||||
ARTIFACT_URL = "https://w9artifact.blob.core.windows.net/release/websoft9"
|
||||
ARTIFACT_URL_DEV = "https://w9artifact.blob.core.windows.net/dev/websoft9"
|
||||
|
|
6
appmanage/api/utils/helper.py
Normal file
6
appmanage/api/utils/helper.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
class Singleton(type):
|
||||
_instances = {}
|
||||
def __call__(cls, *args, **kwargs):
|
||||
if cls not in cls._instances:
|
||||
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
|
||||
return cls._instances[cls]
|
0
appmanage/api/v1/__init__.py
Normal file
0
appmanage/api/v1/__init__.py
Normal file
|
@ -1,6 +1,6 @@
|
|||
from fastapi import APIRouter
|
||||
|
||||
from api.v1.routers import health,apps
|
||||
from api.v1.routers import health, apps
|
||||
|
||||
|
||||
def get_api():
|
||||
|
|
0
appmanage/api/v1/routers/__init__.py
Normal file
0
appmanage/api/v1/routers/__init__.py
Normal file
|
@ -11,6 +11,7 @@ from api.service import manage, db
|
|||
from api.utils import shell_execute, const
|
||||
from api.utils.common_log import myLogger
|
||||
from api.exception.command_exception import CommandException
|
||||
from api.settings.settings import settings
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
@ -76,10 +77,17 @@ rd_appstore = rd_s + appstore_update + rd_e
|
|||
rd_auto_list = rd_s + auto + rd_e
|
||||
rd_user_list = rd_s + user + rd_e
|
||||
rd_updateuser_list=rd_s + updateuser + rd_e
|
||||
|
||||
|
||||
class SettingItem(BaseModel):
|
||||
|
||||
key: str = Field(description="配置项")
|
||||
value: str = Field(description="配置项的取值")
|
||||
|
||||
@router.api_route("/AppStatus", methods=["GET", "POST"], summary="获取指定APP的信息",
|
||||
response_description=rd_status,
|
||||
response_model=Response)
|
||||
def AppStatus(request: Request,app_id: Optional[str] = Query(default=None, description="应用ID")):
|
||||
def AppStatus(request: Request, app_id: Optional[str] = Query(default=None, description="应用ID")):
|
||||
try:
|
||||
myLogger.info_logger("Receive request: /AppStatus")
|
||||
get_headers(request)
|
||||
|
@ -526,6 +534,27 @@ def AppUpdateUser(request: Request,user_name: Optional[str] = Query(default=None
|
|||
|
||||
return response
|
||||
|
||||
|
||||
@router.api_route("/AppListSettings", methods=['GET', 'POST'], summary="获取配置信息")
|
||||
def list_settings():
|
||||
items = settings.list_all_settings()
|
||||
return [{
|
||||
'key': key,
|
||||
'value': value
|
||||
} for key, value in items.items()]
|
||||
|
||||
|
||||
@router.api_route("/AppUpdateSettings", methods=['GET', 'POST'], summary="创建或者更新配置信息")
|
||||
def create_or_update_settings(item: SettingItem):
|
||||
settings.update_setting(item.key, item.value)
|
||||
|
||||
|
||||
|
||||
@router.api_route("/AppDeleteSettings", methods=['GET', 'POST'], summary="删除配置信息")
|
||||
def delete_settings(item: SettingItem):
|
||||
settings.delete_setting(item.key, item.value)
|
||||
|
||||
|
||||
def get_headers(request):
|
||||
headers = request.headers
|
||||
try:
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import api.v1.api as api_router_v1
|
||||
import argparse
|
||||
import uvicorn
|
||||
from api.utils.common_log import myLogger
|
||||
from api.utils import shell_execute
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
|
@ -11,10 +10,19 @@ from fastapi.openapi.docs import (
|
|||
get_swagger_ui_oauth2_redirect_html,
|
||||
)
|
||||
|
||||
import api.v1.api as api_router_v1
|
||||
|
||||
from api.utils.common_log import myLogger
|
||||
from api.utils import shell_execute
|
||||
from api.settings.settings import settings
|
||||
|
||||
|
||||
myLogger.info_logger("Start server...")
|
||||
app = FastAPI(docs_url=None, redoc_url=None, openapi_url="/")
|
||||
|
||||
def get_app():
|
||||
|
||||
def get_app():
|
||||
settings.init_config_from_file()
|
||||
origins = [
|
||||
"http://localhost",
|
||||
"http://localhost:9090",
|
||||
|
@ -45,6 +53,7 @@ async def custom_swagger_ui_html():
|
|||
async def swagger_ui_redirect():
|
||||
return get_swagger_ui_oauth2_redirect_html()
|
||||
|
||||
|
||||
@app.get("/redoc", include_in_schema=False)
|
||||
async def redoc_html():
|
||||
return get_redoc_html(
|
||||
|
@ -54,4 +63,9 @@ async def redoc_html():
|
|||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
uvicorn.run("main:get_app", host='0.0.0.0', port=5000, reload=True)
|
||||
parser = argparse.ArgumentParser(description='websoft9')
|
||||
parser.add_argument("--port", type=int, dest='port', default=5000, metavar="port")
|
||||
parser.add_argument("--config", type=str, dest="config_file", required=True)
|
||||
args = parser.parse_args()
|
||||
settings.init_config_from_file(config_file=args.config_file)
|
||||
uvicorn.run("main:get_app", host='0.0.0.0', port=args.port, reload=True)
|
0
test/__init__.py
Normal file
0
test/__init__.py
Normal file
0
test/settings/__init__.py
Normal file
0
test/settings/__init__.py
Normal file
46
test/settings/test_settings.py
Normal file
46
test/settings/test_settings.py
Normal file
|
@ -0,0 +1,46 @@
|
|||
import os
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
from appmanage.api.settings.settings import settings
|
||||
|
||||
|
||||
class TestSettings(unittest.TestCase):
|
||||
fd = None
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
fd = tempfile.NamedTemporaryFile("w")
|
||||
print(fd.name)
|
||||
fd.write("a=b\nc=d\n")
|
||||
fd.flush()
|
||||
settings.init_config_from_file(fd.name)
|
||||
|
||||
def test_get_config(self):
|
||||
self.assertEqual(settings.get_setting("a"), "b")
|
||||
self.assertTrue(settings.get_setting("e") is None)
|
||||
|
||||
def test_update_config(self):
|
||||
self.assertEqual(settings.get_setting("a"), "b")
|
||||
settings.update_setting("a", "i")
|
||||
self.assertEqual(settings.get_setting("a"), "i")
|
||||
|
||||
def test_list_settings(self):
|
||||
data = settings.list_all_settings()
|
||||
self.assertTrue(data is not None)
|
||||
|
||||
def test_delete_config(self):
|
||||
settings.update_setting("x", "y")
|
||||
v = settings.get_setting("x")
|
||||
self.assertTrue(v is not None)
|
||||
settings.delete_setting("x", v)
|
||||
self.assertTrue(settings.get_setting("x") is None)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
if cls.fd:
|
||||
cls.fd.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
Loading…
Reference in a new issue