1
0
mirror of https://github.com/1Panel-dev/1Panel.git synced 2025-01-19 16:29:17 +08:00

feat: 增加反向代理类型

This commit is contained in:
zhengkunwang223 2022-12-12 15:36:45 +08:00 committed by zhengkunwang223
parent 6260281cac
commit b7d55801cd
14 changed files with 84 additions and 47 deletions

View File

@ -100,7 +100,7 @@ func (b *BaseApi) RecoverWebsite(c *gin.Context) {
} }
func (b *BaseApi) DeleteWebSite(c *gin.Context) { func (b *BaseApi) DeleteWebSite(c *gin.Context) {
var req dto.WebSiteDel var req request.WebSiteDel
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return return

View File

@ -21,6 +21,7 @@ type WebSiteCreate struct {
Alias string `json:"alias" validate:"required"` Alias string `json:"alias" validate:"required"`
Remark string `json:"remark"` Remark string `json:"remark"`
OtherDomains string `json:"otherDomains"` OtherDomains string `json:"otherDomains"`
Proxy string `json:"proxy"`
AppType AppType `json:"appType"` AppType AppType `json:"appType"`
AppInstall NewAppInstall `json:"appInstall"` AppInstall NewAppInstall `json:"appInstall"`
AppID uint `json:"appID"` AppID uint `json:"appID"`
@ -45,12 +46,6 @@ type NewAppInstall struct {
Params map[string]interface{} `json:"params"` Params map[string]interface{} `json:"params"`
} }
type WebSiteDel struct {
ID uint `json:"id"`
DeleteApp bool `json:"deleteApp"`
DeleteBackup bool `json:"deleteBackup"`
}
type WebSiteRecover struct { type WebSiteRecover struct {
WebsiteName string `json:"websiteName" validate:"required"` WebsiteName string `json:"websiteName" validate:"required"`
Type string `json:"type" validate:"required"` Type string `json:"type" validate:"required"`

View File

@ -14,6 +14,7 @@ type WebSite struct {
AppInstallID uint `gorm:"type:integer" json:"appInstallId"` AppInstallID uint `gorm:"type:integer" json:"appInstallId"`
WebSiteGroupID uint `gorm:"type:integer" json:"webSiteGroupId"` WebSiteGroupID uint `gorm:"type:integer" json:"webSiteGroupId"`
WebSiteSSLID uint `gorm:"type:integer" json:"webSiteSSLId"` WebSiteSSLID uint `gorm:"type:integer" json:"webSiteSSLId"`
Proxy string `gorm:"type:varchar(128);not null" json:"proxy"`
Domains []WebSiteDomain `json:"domains"` Domains []WebSiteDomain `json:"domains"`
WebSiteSSL WebSiteSSL `json:"webSiteSSL"` WebSiteSSL WebSiteSSL `json:"webSiteSSL"`
} }

View File

@ -11,3 +11,10 @@ type WebsiteWafUpdate struct {
Key string `json:"key" validate:"required"` Key string `json:"key" validate:"required"`
Enable bool `json:"enable" validate:"required"` Enable bool `json:"enable" validate:"required"`
} }
type WebSiteDel struct {
ID uint `json:"id" validate:"required"`
DeleteApp bool `json:"deleteApp"`
DeleteBackup bool `json:"deleteBackup"`
ForceDelete bool `json:"forceDelete"`
}

View File

@ -33,7 +33,7 @@ type IWebsiteService interface {
Recover(req dto.WebSiteRecover) error Recover(req dto.WebSiteRecover) error
RecoverByUpload(req dto.WebSiteRecoverByFile) error RecoverByUpload(req dto.WebSiteRecoverByFile) error
UpdateWebsite(req dto.WebSiteUpdate) error UpdateWebsite(req dto.WebSiteUpdate) error
DeleteWebSite(req dto.WebSiteDel) error DeleteWebSite(req request.WebSiteDel) error
GetWebsite(id uint) (dto.WebsiteDTO, error) GetWebsite(id uint) (dto.WebsiteDTO, error)
CreateWebsiteDomain(create dto.WebSiteDomainCreate) (model.WebSiteDomain, error) CreateWebsiteDomain(create dto.WebSiteDomainCreate) (model.WebSiteDomain, error)
GetWebsiteDomain(websiteId uint) ([]model.WebSiteDomain, error) GetWebsiteDomain(websiteId uint) ([]model.WebSiteDomain, error)
@ -88,9 +88,11 @@ func (w WebsiteService) CreateWebsite(create dto.WebSiteCreate) error {
AppInstallID: create.AppInstallID, AppInstallID: create.AppInstallID,
WebSiteGroupID: create.WebSiteGroupID, WebSiteGroupID: create.WebSiteGroupID,
Protocol: constant.ProtocolHTTP, Protocol: constant.ProtocolHTTP,
Proxy: create.Proxy,
} }
if create.Type == "deployment" { switch create.Type {
case constant.Deployment:
if create.AppType == dto.NewApp { if create.AppType == dto.NewApp {
install, err := ServiceGroupApp.Install(create.AppInstall.Name, create.AppInstall.AppDetailId, create.AppInstall.Params) install, err := ServiceGroupApp.Install(create.AppInstall.Name, create.AppInstall.AppDetailId, create.AppInstall.Params)
if err != nil { if err != nil {
@ -98,7 +100,7 @@ func (w WebsiteService) CreateWebsite(create dto.WebSiteCreate) error {
} }
website.AppInstallID = install.ID website.AppInstallID = install.ID
} }
} else { case constant.Static:
if err := createStaticHtml(website); err != nil { if err := createStaticHtml(website); err != nil {
return err return err
} }
@ -240,12 +242,12 @@ func (w WebsiteService) GetWebsite(id uint) (dto.WebsiteDTO, error) {
return res, nil return res, nil
} }
func (w WebsiteService) DeleteWebSite(req dto.WebSiteDel) error { func (w WebsiteService) DeleteWebSite(req request.WebSiteDel) error {
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.ID)) website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.ID))
if err != nil { if err != nil {
return err return err
} }
if err := delNginxConfig(website); err != nil { if err := delNginxConfig(website, req.ForceDelete); err != nil {
return err return err
} }
tx, ctx := getTxAndContext() tx, ctx := getTxAndContext()
@ -253,7 +255,7 @@ func (w WebsiteService) DeleteWebSite(req dto.WebSiteDel) error {
if req.DeleteApp { if req.DeleteApp {
websites, _ := websiteRepo.GetBy(websiteRepo.WithAppInstallId(website.AppInstallID)) websites, _ := websiteRepo.GetBy(websiteRepo.WithAppInstallId(website.AppInstallID))
if len(websites) > 1 { if len(websites) > 1 {
return errors.New("other website use this app") return buserr.New(constant.ErrAppDelete)
} }
appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID)) appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {

View File

@ -74,7 +74,6 @@ func createStaticHtml(website *model.WebSite) error {
} }
func createWebsiteFolder(nginxInstall model.AppInstall, website *model.WebSite) error { func createWebsiteFolder(nginxInstall model.AppInstall, website *model.WebSite) error {
nginxFolder := path.Join(constant.AppInstallDir, "nginx", nginxInstall.Name) nginxFolder := path.Join(constant.AppInstallDir, "nginx", nginxInstall.Name)
siteFolder := path.Join(nginxFolder, "www", "sites", website.Alias) siteFolder := path.Join(nginxFolder, "www", "sites", website.Alias)
fileOp := files.NewFileOp() fileOp := files.NewFileOp()
@ -99,7 +98,6 @@ func createWebsiteFolder(nginxInstall model.AppInstall, website *model.WebSite)
} }
func configDefaultNginx(website *model.WebSite, domains []model.WebSiteDomain) error { func configDefaultNginx(website *model.WebSite, domains []model.WebSiteDomain) error {
nginxInstall, err := getAppInstallByKey("nginx") nginxInstall, err := getAppInstallByKey("nginx")
if err != nil { if err != nil {
return err return err
@ -131,16 +129,19 @@ func configDefaultNginx(website *model.WebSite, domains []model.WebSiteDomain) e
server.UpdateDirective("set", []string{"$RulePath", path.Join(siteFolder, "waf", "rules")}) server.UpdateDirective("set", []string{"$RulePath", path.Join(siteFolder, "waf", "rules")})
server.UpdateDirective("set", []string{"$logdir", path.Join(siteFolder, "log")}) server.UpdateDirective("set", []string{"$logdir", path.Join(siteFolder, "log")})
if website.Type == "deployment" { switch website.Type {
case constant.Deployment:
appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID)) appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
if err != nil { if err != nil {
return err return err
} }
proxy := fmt.Sprintf("http://127.0.0.1:%d", appInstall.HttpPort) proxy := fmt.Sprintf("http://127.0.0.1:%d", appInstall.HttpPort)
server.UpdateRootProxy([]string{proxy}) server.UpdateRootProxy([]string{proxy})
} else { case constant.Static:
server.UpdateRoot(path.Join("/www/sites", website.Alias)) server.UpdateRoot(path.Join("/www/sites", website.Alias))
server.UpdateRootLocation() server.UpdateRootLocation()
case constant.Proxy:
server.UpdateRootProxy([]string{website.Proxy})
} }
config.FilePath = configPath config.FilePath = configPath
@ -154,8 +155,7 @@ func configDefaultNginx(website *model.WebSite, domains []model.WebSiteDomain) e
return opNginx(nginxInstall.ContainerName, constant.NginxReload) return opNginx(nginxInstall.ContainerName, constant.NginxReload)
} }
func delNginxConfig(website model.WebSite) error { func delNginxConfig(website model.WebSite, force bool) error {
nginxApp, err := appRepo.GetFirst(appRepo.WithKey("nginx")) nginxApp, err := appRepo.GetFirst(appRepo.WithKey("nginx"))
if err != nil { if err != nil {
return err return err
@ -178,11 +178,16 @@ func delNginxConfig(website model.WebSite) error {
if err := fileOp.DeleteFile(configPath); err != nil { if err := fileOp.DeleteFile(configPath); err != nil {
return err return err
} }
return opNginx(nginxInstall.ContainerName, "reload") if err := opNginx(nginxInstall.ContainerName, "reload"); err != nil {
if force {
return nil
}
return err
}
return nil
} }
func addListenAndServerName(website model.WebSite, ports []int, domains []string) error { func addListenAndServerName(website model.WebSite, ports []int, domains []string) error {
nginxFull, err := getNginxFull(&website) nginxFull, err := getNginxFull(&website)
if err != nil { if err != nil {
return nil return nil
@ -203,7 +208,6 @@ func addListenAndServerName(website model.WebSite, ports []int, domains []string
} }
func deleteListenAndServerName(website model.WebSite, ports []int, domains []string) error { func deleteListenAndServerName(website model.WebSite, ports []int, domains []string) error {
nginxFull, err := getNginxFull(&website) nginxFull, err := getNginxFull(&website)
if err != nil { if err != nil {
return nil return nil
@ -280,7 +284,6 @@ func createPemFile(website model.WebSite, websiteSSL model.WebSiteSSL) error {
} }
func applySSL(website model.WebSite, websiteSSL model.WebSiteSSL) error { func applySSL(website model.WebSite, websiteSSL model.WebSiteSSL) error {
nginxFull, err := getNginxFull(&website) nginxFull, err := getNginxFull(&website)
if err != nil { if err != nil {
return nil return nil
@ -398,7 +401,7 @@ func handleWebsiteBackup(backupType, baseDir, backupDir, domain, backupName stri
return err return err
} }
if website.Type == "deployment" { if website.Type == constant.Deployment {
if err := mysqlOpration(&website, "backup", tmpDir); err != nil { if err := mysqlOpration(&website, "backup", tmpDir); err != nil {
return err return err
} }
@ -451,7 +454,7 @@ func handleWebsiteRecover(website *model.WebSite, fileDir string) error {
return err return err
} }
if website.Type == "deployment" { if website.Type == constant.Deployment {
if err := mysqlOpration(website, "recover", fileDir); err != nil { if err := mysqlOpration(website, "recover", fileDir); err != nil {
return err return err
} }

View File

@ -59,6 +59,7 @@ var (
var ( var (
ErrDomainIsExist = "ErrDomainIsExist" ErrDomainIsExist = "ErrDomainIsExist"
ErrAliasIsExist = "ErrAliasIsExist" ErrAliasIsExist = "ErrAliasIsExist"
ErrAppDelete = "ErrAppDelete"
) )
//ssl //ssl

View File

@ -14,3 +14,9 @@ const (
ProtocolHTTP = "HTTP" ProtocolHTTP = "HTTP"
ProtocolHTTPS = "HTTPS" ProtocolHTTPS = "HTTPS"
) )
const (
Deployment = "deployment"
Static = "static"
Proxy = "proxy"
)

View File

@ -30,6 +30,7 @@ ErrFileToLarge: "file is too large"
#website #website
ErrDomainIsExist: "Domain is already exist" ErrDomainIsExist: "Domain is already exist"
ErrAliasIsExist: "Alias is already exist" ErrAliasIsExist: "Alias is already exist"
ErrAppDelete: 'Other Website use this App'
#ssl #ssl
ErrSSLCannotDelete: "The certificate is being used by the website and cannot be removed" ErrSSLCannotDelete: "The certificate is being used by the website and cannot be removed"

View File

@ -29,7 +29,7 @@ ErrFileToLarge: "文件超过10M,无法打开"
#website #website
ErrDomainIsExist: "域名已存在" ErrDomainIsExist: "域名已存在"
ErrAliasIsExist: "代号已存在" ErrAliasIsExist: "代号已存在"
ErrAppDelete: '' ErrAppDelete: '其他网站使用此应用,不能删除'
#ssl #ssl
ErrSSLCannotDelete: "证书正在被网站使用,无法删除" ErrSSLCannotDelete: "证书正在被网站使用,无法删除"

View File

@ -54,6 +54,7 @@ export namespace WebSite {
id: number; id: number;
deleteApp: boolean; deleteApp: boolean;
deleteBackup: boolean; deleteBackup: boolean;
forceDelete: boolean;
} }
export interface WebSiteCreateReq { export interface WebSiteCreateReq {
@ -65,6 +66,7 @@ export namespace WebSite {
appInstallId: number; appInstallId: number;
webSiteGroupId: number; webSiteGroupId: number;
otherDomains: string; otherDomains: string;
proxy: string;
} }
export interface WebSiteUpdateReq { export interface WebSiteUpdateReq {

View File

@ -104,7 +104,7 @@ export default {
imageName: '支持英文中文数字:.-_,长度1-30', imageName: '支持英文中文数字:.-_,长度1-30',
complexityPassword: '请输入 8 位以上必须含有字母数字特殊符号的密码', complexityPassword: '请输入 8 位以上必须含有字母数字特殊符号的密码',
commonPassword: '请输入 6 位以上长度密码', commonPassword: '请输入 6 位以上长度密码',
linuxName: '支持英文数字.-_,长度1-30', linuxName: '支持英文数字._,长度1-30',
email: '请输入正确的邮箱', email: '请输入正确的邮箱',
number: '请输入正确的数字', number: '请输入正确的数字',
ip: '请输入正确的 IP 地址', ip: '请输入正确的 IP 地址',
@ -786,7 +786,7 @@ export default {
otherDomains: '其他域名', otherDomains: '其他域名',
type: '类型', type: '类型',
static: '静态网站', static: '静态网站',
deployment: '反向代理', deployment: '一键部署',
supportUpType: '仅支持 tar.gz 文件', supportUpType: '仅支持 tar.gz 文件',
zipFormat: 'tar.gz 压缩包结构test.tar.gz 压缩包内必需包含 website.json 文件', zipFormat: 'tar.gz 压缩包结构test.tar.gz 压缩包内必需包含 website.json 文件',
proxy: '反向代理', proxy: '反向代理',
@ -868,6 +868,9 @@ export default {
fileExtBlock: '文件扩展名黑名单', fileExtBlock: '文件扩展名黑名单',
value: '值', value: '值',
enable: '开启', enable: '开启',
proxyAddress: '代理地址',
proxyHelper: '例如: http://127.0.0.1:8080',
forceDelete: '强制删除',
}, },
nginx: { nginx: {
serverNamesHashBucketSizeHelper: '服务器名字的hash表大小', serverNamesHashBucketSizeHelper: '服务器名字的hash表大小',

View File

@ -1,17 +1,24 @@
<template> <template>
<el-dialog <el-dialog
v-model="open" v-model="open"
:destroy-on-close="true"
:close-on-click-modal="false" :close-on-click-modal="false"
:title="$t('website.create')" :title="$t('website.create')"
width="40%" width="40%"
:before-close="handleClose" :before-close="handleClose"
> >
<el-form ref="websiteForm" label-position="right" :model="website" label-width="130px" :rules="rules"> <el-form
ref="websiteForm"
label-position="right"
:model="website"
label-width="130px"
:rules="rules"
:validate-on-rule-change="false"
>
<el-form-item :label="$t('website.type')" prop="type"> <el-form-item :label="$t('website.type')" prop="type">
<el-select v-model="website.type"> <el-select v-model="website.type">
<el-option :label="$t('website.deployment')" value="deployment"></el-option> <el-option :label="$t('website.deployment')" value="deployment"></el-option>
<el-option :label="$t('website.static')" value="static"></el-option> <el-option :label="$t('website.static')" value="static"></el-option>
<el-option :label="$t('website.proxy')" value="proxy"></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="$t('website.group')" prop="webSiteGroupId"> <el-form-item :label="$t('website.group')" prop="webSiteGroupId">
@ -103,6 +110,9 @@
<el-form-item :label="$t('website.alias')" prop="alias"> <el-form-item :label="$t('website.alias')" prop="alias">
<el-input v-model="website.alias" :placeholder="$t('website.aliasHelper')"></el-input> <el-input v-model="website.alias" :placeholder="$t('website.aliasHelper')"></el-input>
</el-form-item> </el-form-item>
<el-form-item v-if="website.type === 'proxy'" :label="$t('website.proxyAddress')" prop="proxy">
<el-input v-model="website.proxy" :placeholder="$t('website.proxyHelper')"></el-input>
</el-form-item>
<el-form-item :label="$t('website.remark')" prop="remark"> <el-form-item :label="$t('website.remark')" prop="remark">
<el-input v-model="website.remark"></el-input> <el-input v-model="website.remark"></el-input>
</el-form-item> </el-form-item>
@ -141,6 +151,7 @@ const website = ref({
appInstallId: undefined, appInstallId: undefined,
webSiteGroupId: 1, webSiteGroupId: 1,
otherDomains: '', otherDomains: '',
proxy: '',
appinstall: { appinstall: {
appId: 0, appId: 0,
name: '', name: '',
@ -149,15 +160,16 @@ const website = ref({
version: '', version: '',
}, },
}); });
let rules = ref({ let rules = reactive({
primaryDomain: [Rules.linuxName], primaryDomain: [Rules.linuxName],
alias: [Rules.linuxName], alias: [Rules.linuxName],
type: [Rules.requiredInput], type: [Rules.requiredInput],
webSiteGroupId: [Rules.requiredSelectBusiness], webSiteGroupId: [Rules.requiredSelectBusiness],
appInstallId: [Rules.requiredSelectBusiness], appInstallId: [Rules.requiredSelectBusiness],
appType: [Rules.requiredInput], appType: [Rules.requiredInput],
proxy: [Rules.requiredInput],
appinstall: { appinstall: {
name: [Rules.requiredInput], name: [Rules.linuxName],
appId: [Rules.requiredSelectBusiness], appId: [Rules.requiredSelectBusiness],
params: {}, params: {},
}, },

View File

@ -1,14 +1,14 @@
<template> <template>
<el-dialog <el-dialog
v-model="open" v-model="open"
:destroy-on-close="true"
:close-on-click-modal="false" :close-on-click-modal="false"
:title="$t('website.delete')" :title="$t('website.delete')"
width="40%" width="40%"
:before-close="handleClose" :before-close="handleClose"
> >
<div style="text-align: center"> <div style="text-align: center" :key="key">
<el-checkbox v-model="deleteReq.deleteApp" :label="$t('website.deleteApp')" /> <el-checkbox v-model="deleteReq.forceDelete" :label="$t('website.forceDelete')" />
<el-checkbox v-if="type === 'deployment'" v-model="deleteReq.deleteApp" :label="$t('website.deleteApp')" />
<el-checkbox v-model="deleteReq.deleteBackup" :label="$t('website.deleteBackup')" /> <el-checkbox v-model="deleteReq.deleteBackup" :label="$t('website.deleteBackup')" />
</div> </div>
<template #footer> <template #footer>
@ -26,22 +26,19 @@
import { DeleteWebsite } from '@/api/modules/website'; import { DeleteWebsite } from '@/api/modules/website';
import i18n from '@/lang'; import i18n from '@/lang';
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
import { reactive, ref } from 'vue'; import { ref } from 'vue';
import { WebSite } from '@/api/interface/website';
// interface DeleteProps {
// id: number;
// }
// const deleteData = ref<DeleteProps>({
// id: 0,
// });
let key = 1;
let open = ref(false); let open = ref(false);
let loading = ref(false); let loading = ref(false);
let deleteReq = reactive({ let deleteReq = ref({
id: 0, id: 0,
deleteApp: false, deleteApp: false,
deleteBackup: false, deleteBackup: false,
forceDelete: false,
}); });
let type = ref('');
const em = defineEmits(['close']); const em = defineEmits(['close']);
const handleClose = () => { const handleClose = () => {
@ -49,14 +46,21 @@ const handleClose = () => {
em('close', false); em('close', false);
}; };
const acceptParams = async (id: number) => { const acceptParams = async (website: WebSite.WebSite) => {
deleteReq.id = id; deleteReq.value = {
id: 0,
deleteApp: false,
deleteBackup: false,
forceDelete: false,
};
deleteReq.value.id = website.id;
type.value = website.type;
open.value = true; open.value = true;
}; };
const submit = () => { const submit = () => {
loading.value = true; loading.value = true;
DeleteWebsite(deleteReq) DeleteWebsite(deleteReq.value)
.then(() => { .then(() => {
handleClose(); handleClose();
ElMessage.success(i18n.global.t('commons.msg.deleteSuccess')); ElMessage.success(i18n.global.t('commons.msg.deleteSuccess'));