mirror of
https://github.com/aaPanel/aaPanel.git
synced 2026-08-17 21:25:47 +02:00
Since version 7.7.0, we recommend yours update python to 3.12. [+] Using nginx technology to load static files improves access speed [+] Refactor homepage, website, FTP, and database using vue3 [+] Table loading changed to skeleton screen [+] Add Website statistics-v2 professional plug-in [+] Add Home page - top 5 resource occupancy [+] Add protection for Files management (requires Tamper-proof for Enterprise 3.7) [+] Website, FTP, Databases page add program status [+] Add FTP log analysis (only supports Centos) [+] Add password-free login to phpMyAdmin [+] Add Proxy Project in Website (Supported when web service uses Nginx) [+] Add WP Toolkit (Pro version only) [+] Redesigned Docker module [+] Add WP Toolkit Protection [+] Add WP Toolkit Backup and Restore [+] Add WP Toolkit Migrated [+] Add WP Toolkit Clone site (supports new domain and subdomain) [+] Add WP Toolkit Create site from backup of other panel [+] Add WP Toolkit support for Cron automatic backup (only save Local disk) [+] Add WP Toolkit operation log [+] Add Integrity check for WP Toolkit [+] Add WP Toolkit plug-in management and themes management [*] Optimize phpMyAdmin formula access method [*] Optimize Home page PHP display problem [*] Optimize jump to the login interface after the login expires [*] Optimize automatic renewal of SSL at some times [*] Optimize Let's Encrypt to increase application success rate [-] Fix Logs Audit cannot be opened [-] Fix apache URL rewrite issue [-] Fix phpmyadmin installation problem [-] Fix the problem that some servers cannot install software [-] Fix upload file error [-] Fix left menu hiding problem [-] Fix aaPanel Mobile QR code display problem [-] Fix problem that third-party plug-ins are not displayed in the App Store [-] Fix issue where the menu bar is blank when opening new tabs [-] Fixed panel not being accessible in some cases [-] Fix the issue where Curl warning caused the inability to apply for SSL [-] Fix Quota issues for Website, FTP, Databases [-] Fix file interface display problem on mobile terminal
294 lines
11 KiB
Python
294 lines
11 KiB
Python
# coding: utf-8
|
|
# -------------------------------------------------------------------
|
|
# aaPanel
|
|
# -------------------------------------------------------------------
|
|
# Copyright (c) 2015-2099 aaPanel(www.aapanel.com) All rights reserved.
|
|
# -------------------------------------------------------------------
|
|
# Author: zouhw <zhw@aapanel.com>
|
|
# -------------------------------------------------------------------
|
|
|
|
# ------------------------------
|
|
# Docker模型
|
|
# ------------------------------
|
|
import json
|
|
|
|
import gettext
|
|
_ = gettext.gettext
|
|
|
|
import public
|
|
from btdockerModelV2 import dk_public as dp
|
|
from btdockerModelV2.dockerBase import dockerBase
|
|
from public.validate import Param
|
|
|
|
class main(dockerBase):
|
|
|
|
def docker_client(self, url):
|
|
return dp.docker_client(url)
|
|
|
|
def add(self, args):
|
|
"""
|
|
添加仓库
|
|
:param registry 仓库URL docker.io
|
|
:param name
|
|
:parma username
|
|
:parma password
|
|
:param namespace 仓库命名空间
|
|
:param remark 备注
|
|
:param args:
|
|
:return:
|
|
"""
|
|
# {"registry": "docker.io", "name": "wzznb", "username": "akaishuichi", "password": "xiuyi999..",
|
|
# "namespace": "akaishuichi", "remark": "wzz_docker_io"}
|
|
|
|
# 校验参数
|
|
try:
|
|
args.validate([
|
|
Param('name').Require().String(),
|
|
Param('username').Require().String(),
|
|
Param('password').Require().String(),
|
|
Param('namespace').Require().String(),
|
|
Param('remark').String(),
|
|
|
|
], [
|
|
public.validate.trim_filter(),
|
|
])
|
|
except Exception as ex:
|
|
public.print_log("error info: {}".format(ex))
|
|
return public.return_message(-1, 0, str(ex))
|
|
# 验证登录
|
|
if not args.registry:
|
|
args.registry = "docker.io"
|
|
res = self.login(self._url, args.registry, args.username, args.password)
|
|
if not res['status']:
|
|
return public.return_message(-1, 0, res)
|
|
r_list = self.registry_list(args)
|
|
if len(r_list) > 0:
|
|
for r in r_list:
|
|
if r['name'] == args.name:
|
|
return public.return_message(-1, 0, _( "The name already exists! <br><br>name: {}".format(args.name)))
|
|
if r['username'] == args.username and args.registry == r['url']:
|
|
return public.return_message(-1, 0, _( "Repository information already exists!"))
|
|
pdata = {
|
|
"name": args.name,
|
|
"url": args.registry,
|
|
"namespace": args.namespace,
|
|
"username": public.aes_encrypt(args.username, self.aes_key),
|
|
"password": public.aes_encrypt(args.password, self.aes_key),
|
|
"remark": public.xsssec(args.remark)
|
|
}
|
|
dp.sql("registry").insert(pdata)
|
|
dp.write_log("Added repository [{}] [{}] success!".format(args.name, args.registry))
|
|
return public.return_message(0, 0, _( "successfully added!"))
|
|
|
|
def edit(self, args):
|
|
"""
|
|
编辑仓库
|
|
:param registry 仓库URL docker.io
|
|
:param id 仓库id
|
|
:parma username
|
|
:parma password
|
|
:param namespace
|
|
:param remark
|
|
:param args:
|
|
:return:
|
|
"""
|
|
|
|
# 校验参数
|
|
try:
|
|
args.validate([
|
|
Param('id').Require().Integer(),
|
|
Param('username').Require().String(),
|
|
Param('password').Require().String(),
|
|
Param('namespace').Require().String(),
|
|
Param('remark').String(),
|
|
|
|
], [
|
|
public.validate.trim_filter(),
|
|
])
|
|
except Exception as ex:
|
|
public.print_log("error info: {}".format(ex))
|
|
return public.return_message(-1, 0, str(ex))
|
|
|
|
# 验证登录
|
|
# if str(args.id) == "1":
|
|
# return public.return_message(-1, 0, "[Official Docker repository] Not editable!")
|
|
if not args.registry:
|
|
args.registry = "docker.io"
|
|
|
|
# 2023/12/13 上午 11:40 处理加密的编辑
|
|
try:
|
|
is_encrypt = False
|
|
res = self.login(self._url, args.registry, args.username, args.password)
|
|
if not res['status']:
|
|
res = self.login(
|
|
self._url,
|
|
args.registry,
|
|
public.aes_decrypt(args.username, self.aes_key),
|
|
public.aes_decrypt(args.password, self.aes_key)
|
|
)
|
|
if not res['status']:
|
|
return public.return_message(-1, 0, res['msg'])
|
|
is_encrypt = True
|
|
except Exception as e:
|
|
if "binascii.Error: Incorrect padding" in str(e):
|
|
return public.return_message(-1, 0, _(
|
|
"Editing failed! Reason: Account password decryption failed! Please delete the repository and add it again"))
|
|
return public.return_message(-1, 0, _( "Editing failed! Reason:{}".format(e)))
|
|
|
|
res = dp.sql("registry").where("id=?", (args.id,)).find()
|
|
if not res:
|
|
return public.return_message(-1, 0, _( "This repository could not be found"))
|
|
pdata = {
|
|
"name": args.name,
|
|
"url": args.registry,
|
|
"username": public.aes_encrypt(args.username, self.aes_key) if is_encrypt is False else args.username,
|
|
"password": public.aes_encrypt(args.password, self.aes_key) if is_encrypt is False else args.password,
|
|
"namespace": args.namespace,
|
|
"remark": args.remark
|
|
}
|
|
dp.sql("registry").where("id=?", (args.id,)).update(pdata)
|
|
dp.write_log("Edit repository [{}][{}] Success!".format(args.name, args.registry))
|
|
return public.return_message(0, 0, _( "Edit success!"))
|
|
|
|
def remove(self, args):
|
|
"""
|
|
删除某个仓库
|
|
:param id
|
|
:param rags:
|
|
:return:
|
|
"""
|
|
# 校验参数
|
|
try:
|
|
args.validate([
|
|
Param('id').Require().Integer(),
|
|
], [
|
|
public.validate.trim_filter(),
|
|
])
|
|
except Exception as ex:
|
|
public.print_log("error info: {}".format(ex))
|
|
return public.return_message(-1, 0, str(ex))
|
|
|
|
# if str(args.id) == "1":
|
|
# return public.return_message(-1, 0, "[Official Docker repository] can not be removed!")
|
|
|
|
data = dp.sql("registry").where("id=?", (args.id)).find()
|
|
|
|
if len(data) < 1:
|
|
return public.return_message(0, 0, _( "Delete failed,The repository id may not exist!"))
|
|
|
|
dp.sql("registry").where("id=?", (args.id,)).delete()
|
|
|
|
dp.write_log("Delete repository [{}][{}] Success!".format(data['name'], data['url']))
|
|
return public.return_message(0, 0, _( "Successfully deleted!"))
|
|
def registry_list(self, get):
|
|
"""
|
|
获取仓库列表
|
|
:return:
|
|
"""
|
|
|
|
db_obj = dp.sql("registry")
|
|
# 2024/1/3 下午 6:00 检测数据库是否存在并且表健康
|
|
search_result = db_obj.where('id=? or name=?', (1, "Docker public repository")).select()
|
|
|
|
# if db_obj.ERR_INFO:
|
|
# return []
|
|
|
|
|
|
if len(search_result) == 0:
|
|
dp.sql("registry").insert({
|
|
"name": "Docker public repository",
|
|
"url": "docker.io",
|
|
"username": "",
|
|
"password": "",
|
|
"namespace": "",
|
|
"remark": "Docker public repository"
|
|
})
|
|
if "error: no such table: registry" in search_result or len(search_result) == 0:
|
|
# public.ExecShell("mv -f /www/server/panel/data/docker.db /www/server/panel/data/db/docker.db")
|
|
public.ExecShell("mv -f /www/server/panel/data/db/docker.db /www/server/panel/data/docker.db")
|
|
dp.check_db()
|
|
|
|
res = dp.sql("registry").select()
|
|
if not isinstance(res, list):
|
|
res = []
|
|
return res
|
|
# 改返回
|
|
def registry_listV2(self, get):
|
|
"""
|
|
获取仓库列表
|
|
:return:
|
|
"""
|
|
db_obj = dp.sql("registry")
|
|
# 2024/1/3 下午 6:00 检测数据库是否存在并且表健康
|
|
search_result = db_obj.where('id=? or name=?', (1, "Docker public repository")).select()
|
|
# search_result = db_obj.where('id=? ', (1)).select()
|
|
# if db_obj.ERR_INFO:
|
|
# return public.return_message(0, 0, [])
|
|
|
|
|
|
if len(search_result) == 0:
|
|
dp.sql("registry").insert({
|
|
"name": "Docker public repository",
|
|
"url": "docker.io",
|
|
"username": "",
|
|
"password": "",
|
|
"namespace": "",
|
|
"remark": "Docker public repository"
|
|
})
|
|
if "error: no such table: registry" in search_result or len(search_result) == 0:
|
|
# public.ExecShell("mv -f /www/server/panel/data/docker.db /www/server/panel/data/db/docker.db")
|
|
public.ExecShell("mv -f /www/server/panel/data/db/docker.db /www/server/panel/data/docker.db")
|
|
dp.check_db()
|
|
|
|
res = dp.sql("registry").select()
|
|
if not isinstance(res, list):
|
|
res = []
|
|
|
|
return public.return_message(0, 0, res)
|
|
|
|
def get_com_registry(self, get):
|
|
"""
|
|
获取常用仓库列表
|
|
@param get:
|
|
@return:
|
|
"""
|
|
com_registry_file = "{}/class/btdockerModelV2/config/com_registry.json".format(public.get_panel_path())
|
|
try:
|
|
com_registry = json.loads(public.readFile(com_registry_file))
|
|
except:
|
|
com_registry = {
|
|
"docker.io": "Docker public repository",
|
|
"swr.cn-north-4.myhuaweicloud.com": "Huawei Cloud mirror station",
|
|
"ccr.ccs.tencentyun.com": "Tencent cloud mirror station",
|
|
"registry.cn-hangzhou.aliyuncs.com": "Alibaba Cloud Mirror Station (Hangzhou)"
|
|
}
|
|
|
|
return public.return_message(0, 0, com_registry)
|
|
|
|
def registry_info(self, name):
|
|
return dp.sql("registry").where("name=?", (name,)).find()
|
|
|
|
def login(self, url, registry, username, password):
|
|
"""
|
|
仓库登录测试
|
|
:param args:
|
|
:return:
|
|
"""
|
|
import docker.errors
|
|
try:
|
|
res = self.docker_client(url).login(
|
|
registry=registry,
|
|
username=username,
|
|
password=password,
|
|
reauth=False
|
|
)
|
|
return public.returnMsg(True, str(res))
|
|
except docker.errors.APIError as e:
|
|
if "authentication required" in str(e):
|
|
return public.returnMsg(False,
|
|
"Login test failed! Reason: May be account password error, please check!")
|
|
if "unauthorized: incorrect username or password" in str(e):
|
|
return public.returnMsg(False,
|
|
"Login test failed! Reason: May be account password error, please check!")
|
|
return public.returnMsg(False, "Login test failed! Reason: {}".format(e))
|