This commit is contained in:
Darren 2023-07-20 17:51:24 +08:00 committed by GitHub
parent cb0cf9f758
commit 4cbf0ed576
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 375 additions and 408 deletions

View file

@ -6,7 +6,7 @@
# What is Websoft9? # What is Websoft9?
Websoft9 is web-based PaaS for running 200+ hot [open source application](https://github.com/Websoft9/docker-library/tree/main/apps) on your own server. Websoft9 is web-based PaaS platform for running 200+ hot [open source application](https://github.com/Websoft9/docker-library/tree/main/apps) on your own server.
Websoft9 help you running multiple applications in a single server, that means we believe Microservices on single machine is reasonable. On the contrary, it becomes more and more valuable as computing power increases Websoft9 help you running multiple applications in a single server, that means we believe Microservices on single machine is reasonable. On the contrary, it becomes more and more valuable as computing power increases
@ -44,18 +44,14 @@ You should have root privileges user to install or upgrade Websoft9, if you use
wget https://websoft9.github.io/websoft9/install/install.sh && bash install.sh wget https://websoft9.github.io/websoft9/install/install.sh && bash install.sh
``` ```
When installation completed, you can access it by: **http://Internet IP:9000** and using **Linux user** for login
## Upgrade ## Upgrade
``` ```
curl https://websoft9.github.io/websoft9/install/update.sh | bash curl https://websoft9.github.io/websoft9/install/update.sh | bash
``` ```
## Getting Started
Using local Chrome or Firefox to visit the URL http://domain:9000 name or http://Internet IP:9000, you will enter the websoft9
> Login using the username and password of the Linux operating system
# Contributing # Contributing
Follow the [contributing guidelines](CONTRIBUTING.md) if you want to propose a change in the Websoft9 core. For more information about participating in the community and contributing to the Websoft9 project, see [this page](https://support.websoft9.com/docs/community/contributing). Follow the [contributing guidelines](CONTRIBUTING.md) if you want to propose a change in the Websoft9 core. For more information about participating in the community and contributing to the Websoft9 project, see [this page](https://support.websoft9.com/docs/community/contributing).

View file

@ -1,4 +1,8 @@
# 概述 # AppManage
appmange 是软件商店的一个重要微服务管理商店App的安装、卸载、启动、停止以及查询功能。 AppManage is the core of Websoft9 which can manage application: Create, Stop, Uninstall, Listing
* [API-design](docs/API-design.md)
* [Architecture](docs/architecture.md)
* [Developer](docs/developer.md)

View file

@ -0,0 +1,289 @@
# API Design
## API 结构
### 请求
#### 请求方式
支持如下两种调用方式:
- get
- post
#### 请求头(公共参数)
| 参数名称 | 用途 | 类型 | 必要性 |
| -------- | ------------ | ------ | ------ |
| Version | 接口版本 | string | 可选 |
| Language | 接口显示语言 | string | 可选 |
#### 安全验证
本微服务没有安全验证模块,需通过 API 网关实现
#### 请求主体
[业务接口详情](#业务接口详情)
### 响应结果
#### 响应头(公共参数)
| 返回参数 | 用途 | 类型 | 必要性 |
| ----------- | ---------------------------------- | ------- | ------ |
| HTTP 状态码 | 判断接口调用是否成功200 或 404 | Integer | 必须 |
#### 响应主体
| 返回参数 | 用途 | 类型 | 必要性 |
| ------------ | -------------------- | -------------------- | ---------------------- |
| ResponseData | 各个接口的业务数据 | object(依据接口而异) | 必须 |
| Error | 错误 code 和错误信息 | ErrorInfo | 非必须 ,无错误时不返回 |
```
{
"ResponseData": {
app_id: "xxxx",
StatusReason: {
Code: "Requirement.NotEnough",
Message: "Insufficient system resources (cpu, memory, disk space).",
Detail: "Error detail information"
}
},
"Error": {
Code: "Requirement.NotEnough",
Message: "Insufficient system resources (cpu, memory, disk space).",
Detail: "Error detail information"
}
}
```
#### 错误代码设计
错误代码参考 [AWS API](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/errors-overview.html) 的分类方式:
- Client errors: These errors are usually caused by something the client did, such as specifying an incorrect or invalid parameter in the request, or using an action or resource on behalf of a user that doesn't have permission to use the action or resource. These errors are accompanied by a 400-series HTTP response code.
- Server errors: These errors are usually caused by an AWS server-side issue. These errors are accompanied by a 500-series HTTP response code.
##### Client errors
| code | message | detail |
| ------------------------------------- | -------------- | ------ |
| Client.Parameter.Blank.Error | p 必填参数为空 | null |
| Client.Parameter.Format.Error | p 参数语法不符 | null |
| Client.Parameter.Value.NotExist.Error | p 参数值错误 | null |
| Client.Parameter.Value.Repeat.Error | p 参数值重复 | null |
##### Server errors
| code | message | detail |
| ---------------------- | ---------------------- | ------------ |
| Server.Container.Error | Docker 返回原始错误 | 错误详细信息 |
| Server.SystemError | 系统原始错误 | 错误详细信息 |
| Server.\*\*\* | 其他可以友好提示的错误 | 错误详细信息 |
## 业务接口详情
各个业务接口的详细说明,公共参数不在这里继续说明。
### App 安装
#### Action
AppInstall
#### 请求参数
| 参数名称 | 用途 | 类型 | 必要性 |
| ----------------- | ------------------ | ------ | ------ |
| app_name | 应用名称 | string | 必须 |
| customer_app_name | 用户自定义应用名称 | string | 必须 |
| app_version | 应用版本 | string | 必须 |
#### 返回结果
| 返回值 | 类型 | 必要性 |
| ------------ | ------------- | ------ |
| ResponseData | String(AppID) | 必须 |
| Error | ErrorInfo | 非必须 |
### App 卸载
#### Action
AppUninstall
#### 请求参数
| 参数名称 | 用途 | 类型 | 必要性 |
| -------- | ---------- | ------ | ------ |
| app_id | 卸载该 app | string | 必须 |
#### 返回结果
| 返回值 | 类型 | 必要性 |
| ------------ | ------------- | ------ |
| ResponseData | String(AppID) | 必须 |
| error | ErrorInfo | 非必须 |
### App 重启
#### Action
AppRestart
#### 请求参数
| 参数名称 | 用途 | 类型 | 必要性 |
| -------- | ---------- | ------ | ------ |
| app_id | 重启该 app | string | 必须 |
#### 返回结果
| 返回值 | 类型 | 必要性 |
| ------------ | ------------- | ------ |
| ResponseData | String(AppID) | 必须 |
| error | ErrorInfo | 非必须 |
### App 启动
#### Action
AppStart
#### 请求参数
| 参数名称 | 用途 | 类型 | 必要性 |
| -------- | ---------- | ------ | ------ |
| app_id | 启动该 app | string | 必须 |
#### 返回结果
| 返回值 | 类型 | 必要性 |
| ------------ | ------------- | ------ |
| ResponseData | String(AppID) | 必须 |
| error | ErrorInfo | 非必须 |
### App 停止
#### Action
AppStop
#### 请求参数
| 参数名称 | 用途 | 类型 | 必要性 |
| -------- | ---------- | ------ | ------ |
| app_id | 停止该 app | string | 必须 |
#### 返回结果
| 返回值 | 类型 | 必要性 |
| ------------ | ------------- | ------ |
| ResponseData | String(AppID) | 必须 |
| error | ErrorInfo | 非必须 |
### App 状态查询
#### Action
AppStatus
#### 请求参数
| 参数名称 | 用途 | 类型 | 必要性 |
| -------- | ----------------- | ------ | ------ |
| app_id | 查询该 app 的信息 | string | 必须 |
#### 返回结果
| 返回值 | 类型 | 必要性 |
| ------------ | ------------- | ------ |
| ResponseData | AppStatusInfo | 必须 |
| error | ErrorInfo | 非必须 |
AppStatusInfo 说明:
```
{
app_id应用ID,
status应用运行状态,[installing(创建中)running(运行中)exited(停止)restarting(反复重启)failed(失败)]
status_reason{ // 只有failed时才有内容
Code错误代码
Message错误提示信息
Detail错误真实信息
}
}
```
### App 列表查询
#### Action
AppList
#### 请求参数
| 参数名称 | 用途 | 类型 | 必要性 |
| -------- | -------------- | ------ | ------ |
| app_id | 查询指定的 app | string | 非必须 |
#### 返回结果
| 返回值 | 类型 | 必要性 |
| ------------ | ---------------------- | ------ |
| ResponseData | Array of AppDetailInfo | 必须 |
| error | ErrorInfo | 非必须 |
AppDetailInfo 说明:
```
{
app_id应用ID,
name应用名,
customer_name自定义应用名,
trade_mark应用商标,
status应用运行状态,[installing(创建中)running(运行中)exited(停止)restarting(反复重启)failed(失败)]
status_reason{ // 只有failed时才有内容
Code错误代码
Message错误提示信息
Detail错误真实信息
},
official_app是否为官方应用,
image_url图片路径,
running_info: { // 只有status=running才有值其他时候为空
port应用端口,
compose_filedocker compose文件路径,
url应用网址,
admin_url管理员网址,
user_name用户名,
password密码,
default_domain: 默认域名,
set_domain: 用户自定义域名,
}
}
```

View file

@ -1,22 +0,0 @@
# Administrator 管理手册
## 环境
### 安装组件
1. python 环境
确保安装 python3.6+
2. python 的 pip 包 fastapi,uvicorn[standard],gunicorn
```
pip install -r requirements.txt
```
3. 安装 docker 以及 docker compose、创建 docker 网络 websoft9
### 启动
```
git clone https://github.com/Websoft9/stackhub.git && cd stackhub/docker/appmanage && docker compose up -d
```

View file

@ -1,37 +1,82 @@
# appmanage # Architecture
![image](https://user-images.githubusercontent.com/43192516/231104572-a57940b1-273b-4761-ae82-7139a8966f70.png) AppManage is develop by Python3.10, use [FastAPI](https://github.com/Websoft9/stackhub/blob/main/appmanage/docs/developer.md), [RQ](https://python-rq.org/), logging packages and Redis, Sqlite for data storage
It have the privilege of host machine, and running below jobs on host:
* docker and docker compose
* modify file
## RQ ## Asynchronous jobs - RQ
### 设计 Create application by docker some time need many time, so we use [RQ](https://python-rq.org/) for queueing jobs and processing them in the background with workers
RQ 用于异步处理**创建应用**的事务任务,需保证任务成功或失败后续处理。 ![image](images/rq.png)
它提供的状态有:
- creating: 创建中
- failed: 创建失败
### RQ status RQ sample for development:
RQ 主要解决创建应用的状态 ```
# Job started
rq worker --url redis://websoft9-redis:6379/0
![image](https://user-images.githubusercontent.com/43192516/231103506-22bbfc80-f31f-4ba0-a331-4a05a345ec25.png) # RQ 队列创建:
## 指定 Redis 容器的主机名和端口
redis_conn = Redis(host='websoft9-redis', port=6379)
## docker compose status ## 使用指定的 Redis 连接创建 RQ 队列
q = Queue(connection=redis_conn,default_timeout=3600)
- running: 运行中 #RQ 队列新增排队任务:
- exited: 停止 q.enqueue(install_app_delay, app_name, customer_name, app_version, job_id=app_id)
- restarting: 重启
- created: 创建失败
## API status #获取队列中任务的信息
## 获取 StartedJobRegistry 实例
started = StartedJobRegistry(queue=q)
finish = FinishedJobRegistry(queue=q)
deferred = DeferredJobRegistry(queue=q)
failed = FailedJobRegistry(queue=q)
scheduled = ScheduledJobRegistry(queue=q)
cancel = CanceledJobRegistry(queue=q)
## 获取正在执行的作业 ID 列表
run_job_ids = started.get_job_ids()
finish_job_ids = finish.get_job_ids()
wait_job_ids = deferred.get_job_ids()
failed_jobs = failed.get_job_ids()
scheduled_jobs = scheduled.get_job_ids()
cancel_jobs = cancel.get_job_ids()
```
## Logs partition
```
logPath = 'logs/'
if not os.path.exists(logPath):
os.makedirs(logPath)
logName = 'app_manage.log'
logFile = logPath + logName
formatter = logging.Formatter('%(asctime)s %(levelname)s: %(message)s')
# handler
time_rotating_file_handler = handlers.TimedRotatingFileHandler(filename=logFile, when="MIDNIGHT", interval=1, encoding='utf-8')
time_rotating_file_handler.setLevel(logging.DEBUG)
time_rotating_file_handler.setFormatter(formatter)
```
## Application Status
Application status is very import for developer to understand AppManage, it combine the [Docker compose status](https://docs.docker.com/engine/reference/commandline/compose_ps/#options) and [RQ status](https://python-rq.org/docs/job_registries/)
- installing(创建中): 来源于 RQ 的queue或StartedJobRegistry 可进行操作[无法进行任何操作] - installing(创建中): 来源于 RQ 的queue或StartedJobRegistry 可进行操作[无法进行任何操作]
- running(运行中): 来源于docker compose可进行操作[所有操作] - running(运行中): 来源于docker compose可进行操作[所有操作]
- exited(停止): 来源于docker compose可进行操作[Start,Restart,Uninstall,日志查看] - exited(停止): 来源于docker compose可进行操作[Start,Restart,Uninstall,日志查看]
- restarting(反复重启): 来源于docker compose可进行操作[Stop,Restart,Uninstall,日志查看] - restarting(反复重启): 来源于docker compose可进行操作[Stop,Restart,Uninstall,日志查看]
- failed(失败): 来源于 docker compose 中的 created || RQ 的 FailedJobRegistry 可进行操作[Uninstall] - failed(失败): 来源于 docker compose 中的 created || RQ 的 FailedJobRegistry 可进行操作[Uninstall]
> docker compose have status: [paused | restarting | removing | running | dead | created | exited]
## API
FastAPI can create API and API docs of swagger, you can get [API design details](API-design.md)

View file

@ -1,289 +1,19 @@
# API 设计文档 # Developer
## API 结构 ## Deployment
### 请求 Install python3.6+ and Docker, then
#### 请求方式
支持如下两种调用方式:
- get
- post
#### 请求头(公共参数)
| 参数名称 | 用途 | 类型 | 必要性 |
| -------- | ------------ | ------ | ------ |
| Version | 接口版本 | string | 可选 |
| Language | 接口显示语言 | string | 可选 |
#### 安全验证
本微服务没有安全验证模块,需通过 API 网关实现
#### 请求主体
[业务接口详情](#业务接口详情)
### 响应结果
#### 响应头(公共参数)
| 返回参数 | 用途 | 类型 | 必要性 |
| ----------- | ---------------------------------- | ------- | ------ |
| HTTP 状态码 | 判断接口调用是否成功200 或 404 | Integer | 必须 |
#### 响应主体
| 返回参数 | 用途 | 类型 | 必要性 |
| ------------ | -------------------- | -------------------- | ---------------------- |
| ResponseData | 各个接口的业务数据 | object(依据接口而异) | 必须 |
| Error | 错误 code 和错误信息 | ErrorInfo | 非必须 ,无错误时不返回 |
``` ```
{ pip install -r requirements.txt
"ResponseData": { docker network create websoft9
app_id: "xxxx", git clone https://github.com/Websoft9/stackhub.git && cd stackhub/docker/appmanage && docker compose up -d
StatusReason: {
Code: "Requirement.NotEnough",
Message: "Insufficient system resources (cpu, memory, disk space).",
Detail: "Error detail information"
}
},
"Error": {
Code: "Requirement.NotEnough",
Message: "Insufficient system resources (cpu, memory, disk space).",
Detail: "Error detail information"
}
}
``` ```
#### 错误代码设计 ## API UI
错误代码参考 [AWS API](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/errors-overview.html) 的分类方式: Access API by: **http://Internet IP:port/docs**
- Client errors: These errors are usually caused by something the client did, such as specifying an incorrect or invalid parameter in the request, or using an action or resource on behalf of a user that doesn't have permission to use the action or resource. These errors are accompanied by a 400-series HTTP response code. ### Test Automation
- Server errors: These errors are usually caused by an AWS server-side issue. These errors are accompanied by a 500-series HTTP response code. Coming soon...
##### Client errors
| code | message | detail |
| ------------------------------------- | -------------- | ------ |
| Client.Parameter.Blank.Error | p 必填参数为空 | null |
| Client.Parameter.Format.Error | p 参数语法不符 | null |
| Client.Parameter.Value.NotExist.Error | p 参数值错误 | null |
| Client.Parameter.Value.Repeat.Error | p 参数值重复 | null |
##### Server errors
| code | message | detail |
| ---------------------- | ---------------------- | ------------ |
| Server.Container.Error | Docker 返回原始错误 | 错误详细信息 |
| Server.SystemError | 系统原始错误 | 错误详细信息 |
| Server.\*\*\* | 其他可以友好提示的错误 | 错误详细信息 |
## 业务接口详情
各个业务接口的详细说明,公共参数不在这里继续说明。
### App 安装
#### Action
AppInstall
#### 请求参数
| 参数名称 | 用途 | 类型 | 必要性 |
| ----------------- | ------------------ | ------ | ------ |
| app_name | 应用名称 | string | 必须 |
| customer_app_name | 用户自定义应用名称 | string | 必须 |
| app_version | 应用版本 | string | 必须 |
#### 返回结果
| 返回值 | 类型 | 必要性 |
| ------------ | ------------- | ------ |
| ResponseData | String(AppID) | 必须 |
| Error | ErrorInfo | 非必须 |
### App 卸载
#### Action
AppUninstall
#### 请求参数
| 参数名称 | 用途 | 类型 | 必要性 |
| -------- | ---------- | ------ | ------ |
| app_id | 卸载该 app | string | 必须 |
#### 返回结果
| 返回值 | 类型 | 必要性 |
| ------------ | ------------- | ------ |
| ResponseData | String(AppID) | 必须 |
| error | ErrorInfo | 非必须 |
### App 重启
#### Action
AppRestart
#### 请求参数
| 参数名称 | 用途 | 类型 | 必要性 |
| -------- | ---------- | ------ | ------ |
| app_id | 重启该 app | string | 必须 |
#### 返回结果
| 返回值 | 类型 | 必要性 |
| ------------ | ------------- | ------ |
| ResponseData | String(AppID) | 必须 |
| error | ErrorInfo | 非必须 |
### App 启动
#### Action
AppStart
#### 请求参数
| 参数名称 | 用途 | 类型 | 必要性 |
| -------- | ---------- | ------ | ------ |
| app_id | 启动该 app | string | 必须 |
#### 返回结果
| 返回值 | 类型 | 必要性 |
| ------------ | ------------- | ------ |
| ResponseData | String(AppID) | 必须 |
| error | ErrorInfo | 非必须 |
### App 停止
#### Action
AppStop
#### 请求参数
| 参数名称 | 用途 | 类型 | 必要性 |
| -------- | ---------- | ------ | ------ |
| app_id | 停止该 app | string | 必须 |
#### 返回结果
| 返回值 | 类型 | 必要性 |
| ------------ | ------------- | ------ |
| ResponseData | String(AppID) | 必须 |
| error | ErrorInfo | 非必须 |
### App 状态查询
#### Action
AppStatus
#### 请求参数
| 参数名称 | 用途 | 类型 | 必要性 |
| -------- | ----------------- | ------ | ------ |
| app_id | 查询该 app 的信息 | string | 必须 |
#### 返回结果
| 返回值 | 类型 | 必要性 |
| ------------ | ------------- | ------ |
| ResponseData | AppStatusInfo | 必须 |
| error | ErrorInfo | 非必须 |
AppStatusInfo 说明:
```
{
app_id应用ID,
status应用运行状态,[installing(创建中)running(运行中)exited(停止)restarting(反复重启)failed(失败)]
status_reason{ // 只有failed时才有内容
Code错误代码
Message错误提示信息
Detail错误真实信息
}
}
```
### App 列表查询
#### Action
AppList
#### 请求参数
| 参数名称 | 用途 | 类型 | 必要性 |
| -------- | -------------- | ------ | ------ |
| app_id | 查询指定的 app | string | 非必须 |
#### 返回结果
| 返回值 | 类型 | 必要性 |
| ------------ | ---------------------- | ------ |
| ResponseData | Array of AppDetailInfo | 必须 |
| error | ErrorInfo | 非必须 |
AppDetailInfo 说明:
```
{
app_id应用ID,
name应用名,
customer_name自定义应用名,
trade_mark应用商标,
status应用运行状态,[installing(创建中)running(运行中)exited(停止)restarting(反复重启)failed(失败)]
status_reason{ // 只有failed时才有内容
Code错误代码
Message错误提示信息
Detail错误真实信息
},
official_app是否为官方应用,
image_url图片路径,
running_info: { // 只有status=running才有值其他时候为空
port应用端口,
compose_filedocker compose文件路径,
url应用网址,
admin_url管理员网址,
user_name用户名,
password密码,
default_domain: 默认域名,
set_domain: 用户自定义域名,
}
}
```

View file

@ -1,9 +0,0 @@
## 使用
### API
安装 appmanage 后可使用浏览器或Postman访问接口自动生成文档地址http://ip:port/redoc 或 http://ip:port/docs
### CLI
暂未提供

Binary file not shown.

After

Width:  |  Height:  |  Size: 7 KiB

3
appmanage/test/README.md Normal file
View file

@ -0,0 +1,3 @@
# Test
Automatic testing script for API

View file

@ -1,75 +1,6 @@
# Developer Guide # Developer Guide
## Appmanage
### 开发环境以及组件
Python3.10, FastAPI, RQ, logging
### 关键技术实现
#### 日志分割
```
logPath = 'logs/'
if not os.path.exists(logPath):
os.makedirs(logPath)
logName = 'app_manage.log'
logFile = logPath + logName
formatter = logging.Formatter('%(asctime)s %(levelname)s: %(message)s')
# handler
time_rotating_file_handler = handlers.TimedRotatingFileHandler(filename=logFile, when="MIDNIGHT", interval=1, encoding='utf-8')
time_rotating_file_handler.setLevel(logging.DEBUG)
time_rotating_file_handler.setFormatter(formatter)
```
#### RQ
任务管理器启动:
```
rq worker --url redis://websoft9-redis:6379/0
```
RQ 队列创建:
```
# 指定 Redis 容器的主机名和端口
redis_conn = Redis(host='websoft9-redis', port=6379)
# 使用指定的 Redis 连接创建 RQ 队列
q = Queue(connection=redis_conn,default_timeout=3600)
```
RQ 队列新增排队任务:
```
q.enqueue(install_app_delay, app_name, customer_name, app_version, job_id=app_id)
```
获取队列中任务的信息:
```
# 获取 StartedJobRegistry 实例
started = StartedJobRegistry(queue=q)
finish = FinishedJobRegistry(queue=q)
deferred = DeferredJobRegistry(queue=q)
failed = FailedJobRegistry(queue=q)
scheduled = ScheduledJobRegistry(queue=q)
cancel = CanceledJobRegistry(queue=q)
# 获取正在执行的作业 ID 列表
run_job_ids = started.get_job_ids()
finish_job_ids = finish.get_job_ids()
wait_job_ids = deferred.get_job_ids()
failed_jobs = failed.get_job_ids()
scheduled_jobs = scheduled.get_job_ids()
cancel_jobs = cancel.get_job_ids()
```
### API 文档
[FastAPI 文档](https://github.com/Websoft9/stackhub/blob/main/appmanage/docs/developer.md) 使用 swagger 自动生成访问地址http://IP:PORT/docs。
## 版本管理 ## 版本管理

View file